From 28e9566dc539244b3b429c21c556d656733839c2 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Wed, 22 Nov 2017 21:09:31 +0100 Subject: [PATCH] spin: Update to most recent version. (thanks Ori_B) from Ori_B: There were a small number of changes needed from the tarball on spinroot.org: - The mkfile needed to be updated - Memory.h needed to not be included - It needed to invoke /bin/cpp instead of gcc -E - It depended on `yychar`, which our yacc doesn't provide. I'm still figuring out how to use spin, but it seems to do the right thing when testing a few of the examples: % cd $home/src/Spin/Examples/ % spin -a peterson.pml % pcc pan.c -D_POSIX_SOURCE % ./6.out (Spin Version 6.4.7 -- 19 August 2017) + Partial Order Reduction Full statespace search for: never claim - (none specified) assertion violations + acceptance cycles - (not selected) invalid end states + State-vector 32 byte, depth reached 24, errors: 0 40 states, stored 27 states, matched 67 transitions (= stored+matched) 0 atomic steps hash conflicts: 0 (resolved) Stats on memory usage (in Megabytes): 0.002 equivalent memory usage for states (stored*(State-vector + overhead)) 0.292 actual memory usage for states 128.000 memory used for hash table (-w24) 0.534 memory used for DFS stack (-m10000) 128.730 total actual memory usage unreached in proctype user /tmp/Spin/Examples/peterson.pml:20, state 10, "-end-" (1 of 10 states) pan: elapsed time 1.25 seconds pan: rate 32 states/second --- sys/src/cmd/spin/dstep.c | 71 +- sys/src/cmd/spin/flow.c | 452 ++- sys/src/cmd/spin/guided.c | 160 +- sys/src/cmd/spin/main.c | 1107 +++++- sys/src/cmd/spin/mesg.c | 266 +- sys/src/cmd/spin/mkfile | 6 +- sys/src/cmd/spin/msc_tcl.c | 376 ++ sys/src/cmd/spin/pangen1.c | 655 +++- sys/src/cmd/spin/pangen1.h | 6955 ++++++++++++++++++++++++++--------- sys/src/cmd/spin/pangen2.c | 1082 ++++-- sys/src/cmd/spin/pangen2.h | 798 ++-- sys/src/cmd/spin/pangen3.c | 253 +- sys/src/cmd/spin/pangen3.h | 1148 ++++-- sys/src/cmd/spin/pangen4.c | 40 +- sys/src/cmd/spin/pangen4.h | 34 +- sys/src/cmd/spin/pangen5.c | 90 +- sys/src/cmd/spin/pangen5.h | 23 +- sys/src/cmd/spin/pangen6.c | 157 +- sys/src/cmd/spin/pangen6.h | 2878 +++++++++++++++ sys/src/cmd/spin/pangen7.c | 923 +++++ sys/src/cmd/spin/pangen7.h | 2413 ++++++++++++ sys/src/cmd/spin/reprosrc.c | 270 +- sys/src/cmd/spin/run.c | 219 +- sys/src/cmd/spin/sched.c | 296 +- sys/src/cmd/spin/spin.h | 91 +- sys/src/cmd/spin/spin.y | 615 +++- sys/src/cmd/spin/spinlex.c | 908 ++++- sys/src/cmd/spin/structs.c | 76 +- sys/src/cmd/spin/sym.c | 159 +- sys/src/cmd/spin/tl.h | 29 +- sys/src/cmd/spin/tl_buchi.c | 56 +- sys/src/cmd/spin/tl_cache.c | 35 +- sys/src/cmd/spin/tl_lex.c | 150 +- sys/src/cmd/spin/tl_main.c | 95 +- sys/src/cmd/spin/tl_mem.c | 19 +- sys/src/cmd/spin/tl_parse.c | 36 +- sys/src/cmd/spin/tl_rewrt.c | 33 +- sys/src/cmd/spin/tl_trans.c | 77 +- sys/src/cmd/spin/vars.c | 120 +- sys/src/cmd/spin/version.h | 10 +- 40 files changed, 19245 insertions(+), 3936 deletions(-) create mode 100644 sys/src/cmd/spin/msc_tcl.c create mode 100644 sys/src/cmd/spin/pangen6.h create mode 100644 sys/src/cmd/spin/pangen7.c create mode 100644 sys/src/cmd/spin/pangen7.h diff --git a/sys/src/cmd/spin/dstep.c b/sys/src/cmd/spin/dstep.c index f24860309..eb9c634f1 100644 --- a/sys/src/cmd/spin/dstep.c +++ b/sys/src/cmd/spin/dstep.c @@ -1,27 +1,25 @@ /***** spin: dstep.c *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ +#include #include "spin.h" #include "y.tab.h" -#define MAXDSTEP 1024 /* was 512 */ +#define MAXDSTEP 2048 /* was 512 */ -char *NextLab[64]; +char *NextLab[64]; /* must match value in pangen2.c:41 */ int Level=0, GenCode=0, IsGuard=0, TestOnly=0; static int Tj=0, Jt=0, LastGoto=0; static int Tojump[MAXDSTEP], Jumpto[MAXDSTEP], Special[MAXDSTEP]; static void putCode(FILE *, Element *, Element *, Element *, int); -extern int Pid, claimnr, separate, OkBreak; +extern int Pid, separate, OkBreak; static void Sourced(int n, int special) @@ -59,7 +57,7 @@ Mopup(FILE *fd) if (Tojump[j] == Jumpto[i]) break; if (j == Tj) - { char buf[12]; + { char buf[16]; if (Jumpto[i] == OkBreak) { if (!LastGoto) fprintf(fd, "S_%.3d_0: /* break-dest */\n", @@ -80,10 +78,11 @@ Mopup(FILE *fd) } for (j = i = 0; j < Tj; j++) if (Special[j]) - { Tojump[i] = Tojump[j]; + { if (i >= MAXDSTEP) + { fatal("cannot happen (dstep.c)", (char *)0); + } + Tojump[i] = Tojump[j]; Special[i] = 2; - if (i >= MAXDSTEP) - fatal("cannot happen (dstep.c)", (char *)0); i++; } Tj = i; /* keep only the global exit-labels */ @@ -164,7 +163,7 @@ CollectGuards(FILE *fd, Element *e, int inh) break; case ELSE: if (inh++ > 0) fprintf(fd, " || "); -/* 4.2.5 */ if (Pid != claimnr) +/* 4.2.5 */ if (!pid_is_claim(Pid)) fprintf(fd, "(boq == -1 /* else */)"); else fprintf(fd, "(1 /* else */)"); @@ -184,17 +183,17 @@ CollectGuards(FILE *fd, Element *e, int inh) case 's': if (inh++ > 0) fprintf(fd, " || "); fprintf(fd, "("); TestOnly=1; -/* 4.2.1 */ if (Pid != claimnr) fprintf(fd, "(boq == -1) && "); +/* 4.2.1 */ if (!pid_is_claim(Pid)) fprintf(fd, "(boq == -1) && "); putstmnt(fd, ee->n, ee->seqno); fprintf(fd, ")"); TestOnly=0; break; case 'c': if (inh++ > 0) fprintf(fd, " || "); fprintf(fd, "("); TestOnly=1; - if (Pid != claimnr) + if (!pid_is_claim(Pid)) fprintf(fd, "(boq == -1 && "); putstmnt(fd, ee->n->lft, e->seqno); - if (Pid != claimnr) + if (!pid_is_claim(Pid)) fprintf(fd, ")"); fprintf(fd, ")"); TestOnly=0; break; @@ -204,7 +203,8 @@ CollectGuards(FILE *fd, Element *e, int inh) int putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno) -{ int isg=0; char buf[64]; +{ int isg=0; + static char buf[64]; NextLab[0] = "continue"; filterbad(s->frst); @@ -215,6 +215,7 @@ putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno) 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, seqno); + if (justguards) return 0; /* 6.2.5 */ break; case IF: fprintf(fd, "if (!("); @@ -245,7 +246,7 @@ putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno) case 's': fprintf(fd, "if ("); #if 1 -/* 4.2.1 */ if (Pid != claimnr) fprintf(fd, "(boq != -1) || "); +/* 4.2.1 */ if (!pid_is_claim(Pid)) fprintf(fd, "(boq != -1) || "); #endif fprintf(fd, "!("); TestOnly=1; putstmnt(fd, s->frst->n, s->frst->seqno); @@ -253,7 +254,7 @@ putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno) break; case 'c': fprintf(fd, "if (!("); - if (Pid != claimnr) fprintf(fd, "boq == -1 && "); + if (!pid_is_claim(Pid)) fprintf(fd, "boq == -1 && "); TestOnly=1; putstmnt(fd, s->frst->n->lft, s->frst->seqno); fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0; @@ -262,19 +263,31 @@ putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno) fprintf(fd, "if (boq != -1 || ("); if (separate != 2) fprintf(fd, "trpt->"); fprintf(fd, "o_pm&1))\n\t\t\tcontinue;"); + { extern FILE *th; + fprintf(th, "#ifndef ELSE_IN_GUARD\n"); + fprintf(th, " #define ELSE_IN_GUARD\n"); + fprintf(th, "#endif\n"); + } break; case ASGN: /* new 3.0.8 */ fprintf(fd, "IfNotBlocked"); break; + default: + fprintf(fd, "/* default %d */\n\t\t", s->frst->n->ntyp); } + + /* 6.2.5 : before TstOnly */ + fprintf(fd, "\n\n\t\treached[%d][%d] = 1;\n\t\t", Pid, seqno); + fprintf(fd, "reached[%d][t->st] = 1;\n\t\t", Pid); /* next state */ + fprintf(fd, "reached[%d][tt] = 1;\n", Pid); /* current state */ + + /* 6.2.5 : before sv_save() */ + if (s->frst->n->ntyp != NON_ATOMIC) + fprintf(fd, "\n\t\tif (TstOnly) return 1;\n"); /* if called from enabled() */ + if (justguards) return 0; 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); @@ -359,7 +372,7 @@ putCode(FILE *fd, Element *f, Element *last, Element *next, int isguard) case '.': if (LastGoto) break; if (e->nxt && (e->nxt->status & DONE2)) - { i = e->nxt?e->nxt->Seqno:0; + { i = e->nxt->Seqno; fprintf(fd, "\t\tgoto S_%.3d_0;", i); fprintf(fd, " /* '.' */\n"); Dested(i); @@ -375,7 +388,7 @@ putCode(FILE *fd, Element *f, Element *last, Element *next, int isguard) break; } i = e->nxt?e->nxt->Seqno:0; - if (e->nxt && e->nxt->status & DONE2 && !LastGoto) + if (e->nxt && (e->nxt->status & DONE2) && !LastGoto) { fprintf(fd, "\t\tgoto S_%.3d_0; ", i); fprintf(fd, "/* ';' */\n"); Dested(i); diff --git a/sys/src/cmd/spin/flow.c b/sys/src/cmd/spin/flow.c index ac3e4e4b6..1eb43f40f 100644 --- a/sys/src/cmd/spin/flow.c +++ b/sys/src/cmd/spin/flow.c @@ -1,24 +1,24 @@ /***** spin: flow.c *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #include "spin.h" #include "y.tab.h" extern Symbol *Fname; -extern int nr_errs, lineno, verbose; -extern short has_unless, has_badelse; +extern int nr_errs, lineno, verbose, in_for, old_scope_rules, s_trail; +extern short has_unless, has_badelse, has_xu; +extern char CurScope[MAXSCOPESZ]; Element *Al_El = ZE; Label *labtab = (Label *) 0; -int Unique=0, Elcnt=0, DstepStart = -1; +int Unique = 0, Elcnt = 0, DstepStart = -1; +int initialization_ok = 1; +short has_accept; static Lbreak *breakstack = (Lbreak *) 0; static Lextok *innermost; @@ -37,10 +37,16 @@ void open_seq(int top) { SeqList *t; Sequence *s = (Sequence *) emalloc(sizeof(Sequence)); + s->minel = -1; t = seqlist(s, cur_s); cur_s = t; - if (top) Elcnt = 1; + if (top) + { Elcnt = 1; + initialization_ok = 1; + } else + { initialization_ok = 0; + } } void @@ -84,6 +90,7 @@ cross_dsteps(Lextok *a, Lextok *b) && a->indstep != b->indstep) { lineno = a->ln; Fname = a->fn; + if (!s_trail) fatal("jump into d_step sequence", (char *) 0); } } @@ -113,8 +120,8 @@ check_sequence(Sequence *s) && n->ntyp != PRINT && n->ntyp != PRINTM) { if (verbose&32) - printf("spin: line %d %s, redundant skip\n", - n->ln, n->fn->name); + printf("spin: %s:%d, redundant skip\n", + n->fn->name, n->ln); if (e != s->frst && e != s->last && e != s->extent) @@ -147,7 +154,11 @@ close_seq(int nottop) { Sequence *s = cur_s->this; Symbol *z; - if (nottop > 0 && (z = has_lab(s->frst, 0))) + if (nottop == 0) /* end of proctype body */ + { initialization_ok = 1; + } + + if (nottop > 0 && s->frst && (z = has_lab(s->frst, 0))) { printf("error: (%s:%d) label %s placed incorrectly\n", (s->frst->n)?s->frst->n->fn->name:"-", (s->frst->n)?s->frst->n->ln:0, @@ -183,12 +194,12 @@ close_seq(int nottop) printf("\"Label: { statement ... }\"\n"); break; case 6: - printf("=====>instead of\n"); + printf("=====> instead of\n"); printf(" do (or if)\n"); printf(" :: ...\n"); printf(" :: Label: statement\n"); printf(" od (of fi)\n"); - printf("=====>always use\n"); + printf("=====> use\n"); printf("Label: do (or if)\n"); printf(" :: ...\n"); printf(" :: statement\n"); @@ -198,8 +209,9 @@ close_seq(int nottop) printf("cannot happen - labels\n"); break; } - alldone(1); - } + if (nottop != 6) + { alldone(1); + } } if (nottop == 4 && !Rjumpslocal(s->frst, s->last)) @@ -217,13 +229,14 @@ Lextok * do_unless(Lextok *No, Lextok *Es) { SeqList *Sl; Lextok *Re = nn(ZN, UNLESS, ZN, ZN); + Re->ln = No->ln; Re->fn = No->fn; - has_unless++; + if (Es->ntyp == NON_ATOMIC) - Sl = Es->sl; - else + { Sl = Es->sl; + } else { open_seq(0); add_seq(Es); Sl = seqlist(close_seq(1), 0); } @@ -348,6 +361,31 @@ loose_ends(void) /* properly tie-up ends of sub-sequences */ } } } +void +popbreak(void) +{ + if (!breakstack) + fatal("cannot happen, breakstack", (char *) 0); + + breakstack = breakstack->nxt; /* pop stack */ +} + +static Lbreak *ob = (Lbreak *) 0; + +void +safe_break(void) +{ + ob = breakstack; + popbreak(); +} + +void +restore_break(void) +{ + breakstack = ob; + ob = (Lbreak *) 0; +} + static Element * if_seq(Lextok *n) { int tok = n->ntyp; @@ -388,21 +426,26 @@ if_seq(Lextok *n) && prev_z->this->frst->n->ntyp == ELSE) { prev_z->this->frst->n->val = 1; has_badelse++; - non_fatal("dubious use of 'else' combined with i/o,", - (char *)0); + if (has_xu) + { fatal("invalid use of 'else' combined with i/o and xr/xs assertions,", + (char *)0); + } else + { non_fatal("dubious use of 'else' combined with i/o,", + (char *)0); + } nr_errs--; } e->n = nn(n, tok, ZN, ZN); e->n->sl = s; /* preserve as info only */ e->sub = s; - for (z = s; z; prev_z = z, z = z->nxt) + for (z = s; z; z = z->nxt) add_el(t, z->this); /* append target */ if (tok == DO) { add_el(t, cur_s->this); /* target upfront */ t = new_el(nn(n, BREAK, ZN, ZN)); /* break target */ set_lab(break_dest(), t); /* new exit */ - breakstack = breakstack->nxt; /* pop stack */ + popbreak(); } add_el(e, cur_s->this); add_el(t, cur_s->this); @@ -563,33 +606,86 @@ add_seq(Lextok *n) void set_lab(Symbol *s, Element *e) { Label *l; extern Symbol *context; + int cur_uiid = is_inline(); if (!s) return; + for (l = labtab; l; l = l->nxt) - if (l->s == s && l->c == context) + { if (strcmp(l->s->name, s->name) == 0 + && l->c == context + && (old_scope_rules || strcmp((const char *) s->bscp, (const char *) l->s->bscp) == 0) + && l->uiid == cur_uiid) { non_fatal("label %s redeclared", s->name); break; - } + } } + + if (strncmp(s->name, "accept", 6) == 0 + && strncmp(s->name, "accept_all", 10) != 0) + { has_accept = 1; + } + l = (Label *) emalloc(sizeof(Label)); l->s = s; l->c = context; l->e = e; + l->uiid = cur_uiid; l->nxt = labtab; labtab = l; } +static Label * +get_labspec(Lextok *n) +{ Symbol *s = n->sym; + Label *l, *anymatch = (Label *) 0; + int ln; + /* + * try to find a label with the same inline id (uiid) + * but if it doesn't exist, return any other match + * within the same scope + */ + for (l = labtab; l; l = l->nxt) + { if (strcmp(l->s->name, s->name) == 0 /* labelname matches */ + && s->context == l->s->context) /* same scope */ + { +#if 0 + if (anymatch && n->uiid == anymatch->uiid) + { if (0) non_fatal("label %s re-declared", s->name); + } + if (0) + { printf("Label %s uiid now::then %d :: %d bcsp %s :: %s\n", + s->name, n->uiid, l->uiid, s->bscp, l->s->bscp); + printf("get_labspec match on %s %s (bscp goto %s - label %s)\n", + s->name, s->context->name, s->bscp, l->s->bscp); + } +#endif + /* same block scope */ + if (strcmp((const char *) s->bscp, (const char *) l->s->bscp) == 0) + { return l; /* definite match */ + } + /* higher block scope */ + ln = strlen((const char *) l->s->bscp); + if (strncmp((const char *) s->bscp, (const char *) l->s->bscp, ln) == 0) + { anymatch = l; /* possible match */ + } else if (!anymatch) + { anymatch = l; /* somewhere else in same context */ + } } } + + return anymatch; /* return best match */ +} + Element * get_lab(Lextok *n, int md) -{ Label *l; - Symbol *s = n->sym; +{ Label *l = get_labspec(n); - for (l = labtab; l; l = l->nxt) - if (s == l->s) - return (l->e); + if (l != (Label *) 0) + { return (l->e); + } - lineno = n->ln; - Fname = n->fn; - if (md) fatal("undefined label %s", s->name); + if (md) + { lineno = n->ln; + Fname = n->fn; + fatal("undefined label %s", n->sym->name); + } return ZE; } @@ -670,21 +766,46 @@ fix_dest(Symbol *c, Symbol *a) /* c:label name, a:proctype name */ } 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); + { printf("spin: %s:%d, warning, reference to label ", + Fname->name, lineno); + printf("from inside atomic or d_step (%s)\n", c->name); } } int find_lab(Symbol *s, Symbol *c, int markit) -{ Label *l; +{ Label *l, *pm = (Label *) 0, *apm = (Label *) 0; + int ln; + /* generally called for remote references in never claims */ for (l = labtab; l; l = l->nxt) - { if (strcmp(s->name, l->s->name) == 0 + { + if (strcmp(s->name, l->s->name) == 0 && strcmp(c->name, l->c->name) == 0) - { l->visible |= markit; - return (l->e->seqno); - } } + { ln = strlen((const char *) l->s->bscp); + if (0) + { printf("want '%s' in context '%s', scope ref '%s' - label '%s'\n", + s->name, c->name, s->bscp, l->s->bscp); + } + /* same or higher block scope */ + if (strcmp((const char *) s->bscp, (const char *) l->s->bscp) == 0) + { pm = l; /* definite match */ + break; + } + if (strncmp((const char *) s->bscp, (const char *) l->s->bscp, ln) == 0) + { pm = l; /* possible match */ + } else + { apm = l; /* remote */ + } } } + + if (pm) + { pm->visible |= markit; + return pm->e->seqno; + } + if (apm) + { apm->visible |= markit; + return apm->e->seqno; + } /* else printf("Not Found\n"); */ return 0; } @@ -735,6 +856,226 @@ make_atomic(Sequence *s, int added) } } +#if 0 +static int depth = 0; +void dump_sym(Symbol *, char *); + +void +dump_lex(Lextok *t, char *s) +{ int i; + + depth++; + printf(s); + for (i = 0; i < depth; i++) + printf("\t"); + explain(t->ntyp); + if (t->ntyp == NAME) printf(" %s ", t->sym->name); + if (t->ntyp == CONST) printf(" %d ", t->val); + if (t->ntyp == STRUCT) + { dump_sym(t->sym, "\n:Z:"); + } + if (t->lft) + { dump_lex(t->lft, "\nL"); + } + if (t->rgt) + { dump_lex(t->rgt, "\nR"); + } + depth--; +} +void +dump_sym(Symbol *z, char *s) +{ int i; + char txt[64]; + depth++; + printf(s); + for (i = 0; i < depth; i++) + printf("\t"); + + if (z->type == CHAN) + { if (z->ini && z->ini->rgt && z->ini->rgt->sym) + { /* dump_sym(z->ini->rgt->sym, "\n:I:"); -- could also be longer list */ + if (z->ini->rgt->rgt + || !z->ini->rgt->sym) + fatal("chan %s in for should have only one field (a typedef)", z->name); + printf(" -- %s %p -- ", z->ini->rgt->sym->name, z->ini->rgt->sym); + } + } else if (z->type == STRUCT) + { if (z->Snm) + printf(" == %s %p == ", z->Snm->name, z->Snm); + else + { if (z->Slst) + dump_lex(z->Slst, "\n:X:"); + if (z->ini) + dump_lex(z->ini, "\n:I:"); + } + } + depth--; + +} +#endif + +int +match_struct(Symbol *s, Symbol *t) +{ + if (!t + || !t->ini + || !t->ini->rgt + || !t->ini->rgt->sym + || t->ini->rgt->rgt) + { fatal("chan %s in for should have only one field (a typedef)", t?t->name:"--"); + } + /* we already know that s is a STRUCT */ + if (0) + { printf("index type %s %p ==\n", s->Snm->name, s->Snm); + printf("chan type %s %p --\n\n", t->ini->rgt->sym->name, t->ini->rgt->sym); + } + + return (s->Snm == t->ini->rgt->sym); +} + +void +valid_name(Lextok *a3, Lextok *a5, Lextok *a8, char *tp) +{ + if (a3->ntyp != NAME) + { fatal("%s ( .name : from .. to ) { ... }", tp); + } + if (a3->sym->type == CHAN + || a3->sym->type == STRUCT + || a3->sym->isarray != 0) + { fatal("bad index in for-construct %s", a3->sym->name); + } + if (a5->ntyp == CONST && a8->ntyp == CONST && a5->val > a8->val) + { non_fatal("start value for %s exceeds end-value", a3->sym->name); + } +} + +void +for_setup(Lextok *a3, Lextok *a5, Lextok *a8) +{ /* for ( a3 : a5 .. a8 ) */ + + valid_name(a3, a5, a8, "for"); + /* a5->ntyp = a8->ntyp = CONST; */ + add_seq(nn(a3, ASGN, a3, a5)); /* start value */ + open_seq(0); + add_seq(nn(ZN, 'c', nn(a3, LE, a3, a8), ZN)); /* condition */ +} + +Lextok * +for_index(Lextok *a3, Lextok *a5) +{ Lextok *z0, *z1, *z2, *z3; + Symbol *tmp_cnt; + char tmp_nm[MAXSCOPESZ+16]; + /* for ( a3 in a5 ) { ... } */ + + if (a3->ntyp != NAME) + { fatal("for ( .name in name ) { ... }", (char *) 0); + } + + if (a5->ntyp != NAME) + { fatal("for ( %s in .name ) { ... }", a3->sym->name); + } + + if (a3->sym->type == STRUCT) + { if (a5->sym->type != CHAN) + { fatal("for ( %s in .channel_name ) { ... }", + a3->sym->name); + } + z0 = a5->sym->ini; + if (!z0 + || z0->val <= 0 + || z0->rgt->ntyp != STRUCT + || z0->rgt->rgt != NULL) + { fatal("bad channel type %s in for", a5->sym->name); + } + + if (!match_struct(a3->sym, a5->sym)) + { fatal("type of %s does not match chan", a3->sym->name); + } + + z1 = nn(ZN, CONST, ZN, ZN); z1->val = 0; + z2 = nn(a5, LEN, a5, ZN); + + sprintf(tmp_nm, "_f0r_t3mp%s", CurScope); /* make sure it's unique */ + tmp_cnt = lookup(tmp_nm); + if (z0->val > 255) /* check nr of slots, i.e. max length */ + { tmp_cnt->type = SHORT; /* should be rare */ + } else + { tmp_cnt->type = BYTE; + } + z3 = nn(ZN, NAME, ZN, ZN); + z3->sym = tmp_cnt; + + add_seq(nn(z3, ASGN, z3, z1)); /* start value 0 */ + + open_seq(0); + + add_seq(nn(ZN, 'c', nn(z3, LT, z3, z2), ZN)); /* condition */ + + /* retrieve message from the right slot -- for now: rotate contents */ + in_for = 0; + add_seq(nn(a5, 'r', a5, expand(a3, 1))); /* receive */ + add_seq(nn(a5, 's', a5, expand(a3, 1))); /* put back in to rotate */ + in_for = 1; + return z3; + } else + { if (a5->sym->isarray == 0 + || a5->sym->nel <= 0) + { fatal("bad arrayname %s", a5->sym->name); + } + z1 = nn(ZN, CONST, ZN, ZN); z1->val = 0; + z2 = nn(ZN, CONST, ZN, ZN); z2->val = a5->sym->nel - 1; + for_setup(a3, z1, z2); + return a3; + } +} + +Lextok * +for_body(Lextok *a3, int with_else) +{ Lextok *t1, *t2, *t0, *rv; + + rv = nn(ZN, CONST, ZN, ZN); rv->val = 1; + rv = nn(ZN, '+', a3, rv); + rv = nn(a3, ASGN, a3, rv); + add_seq(rv); /* initial increment */ + + /* completed loop body, main sequence */ + t1 = nn(ZN, 0, ZN, ZN); + t1->sq = close_seq(8); + + open_seq(0); /* add else -> break sequence */ + if (with_else) + { add_seq(nn(ZN, ELSE, ZN, ZN)); + } + t2 = nn(ZN, GOTO, ZN, ZN); + t2->sym = break_dest(); + add_seq(t2); + t2 = nn(ZN, 0, ZN, ZN); + t2->sq = close_seq(9); + + t0 = nn(ZN, 0, ZN, ZN); + t0->sl = seqlist(t2->sq, seqlist(t1->sq, 0)); + + rv = nn(ZN, DO, ZN, ZN); + rv->sl = t0->sl; + + return rv; +} + +Lextok * +sel_index(Lextok *a3, Lextok *a5, Lextok *a7) +{ /* select ( a3 : a5 .. a7 ) */ + + valid_name(a3, a5, a7, "select"); + /* a5->ntyp = a7->ntyp = CONST; */ + + add_seq(nn(a3, ASGN, a3, a5)); /* start value */ + open_seq(0); + add_seq(nn(ZN, 'c', nn(a3, LT, a3, a7), ZN)); /* condition */ + + pushbreak(); /* new 6.2.1 */ + return for_body(a3, 0); /* no else, just a non-deterministic break */ +} + static void walk_atomic(Element *a, Element *b, int added) { Element *f; Symbol *ofn; int oln; @@ -747,16 +1088,16 @@ walk_atomic(Element *a, Element *b, int added) switch (f->n->ntyp) { case ATOMIC: if (verbose&32) - printf("spin: warning, line %3d %s, atomic inside %s (ignored)\n", - f->n->ln, f->n->fn->name, (added)?"d_step":"atomic"); + printf("spin: %s:%d, warning, atomic inside %s (ignored)\n", + f->n->fn->name, f->n->ln, (added)?"d_step":"atomic"); goto mknonat; case D_STEP: if (!(verbose&32)) { if (added) goto mknonat; break; } - printf("spin: warning, line %3d %s, d_step inside ", - f->n->ln, f->n->fn->name); + printf("spin: %s:%d, warning, d_step inside ", + f->n->fn->name, f->n->ln); if (added) { printf("d_step (ignored)\n"); goto mknonat; @@ -770,8 +1111,8 @@ mknonat: f->n->ntyp = NON_ATOMIC; /* can jump here */ break; case UNLESS: if (added) - { printf("spin: error, line %3d %s, unless in d_step (ignored)\n", - f->n->ln, f->n->fn->name); + { printf("spin: error, %s:%d, unless in d_step (ignored)\n", + f->n->fn->name, f->n->ln); } } for (h = f->sub; h; h = h->nxt) @@ -789,6 +1130,15 @@ dumplabels(void) for (l = labtab; l; l = l->nxt) if (l->c != 0 && l->s->name[0] != ':') - printf("label %s %d <%s>\n", - l->s->name, l->e->seqno, l->c->name); + { printf("label %s %d ", + l->s->name, l->e->seqno); + if (l->uiid == 0) + printf("<%s>", l->c->name); + else + printf("<%s i%d>", l->c->name, l->uiid); + if (!old_scope_rules) + { printf("\t{scope %s}", l->s->bscp); + } + printf("\n"); + } } diff --git a/sys/src/cmd/spin/guided.c b/sys/src/cmd/spin/guided.c index 0bc4dcbc7..d58e33420 100644 --- a/sys/src/cmd/spin/guided.c +++ b/sys/src/cmd/spin/guided.c @@ -1,17 +1,15 @@ /***** spin: guided.c *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #include "spin.h" #include #include +#include #include "y.tab.h" extern RunList *run, *X; @@ -19,8 +17,9 @@ extern Element *Al_El; extern Symbol *Fname, *oFname; extern int verbose, lineno, xspin, jumpsteps, depth, merger, cutoff; extern int nproc, nstop, Tval, ntrail, columns; -extern short Have_claim, Skip_claim; +extern short Have_claim, Skip_claim, has_code; extern void ana_src(int, int); +extern char **trailfilename; int TstOnly = 0, pno; @@ -73,12 +72,70 @@ not_claim(void) return (!Have_claim || !X || X->pid != 0); } +int globmin = INT_MAX; +int globmax = 0; + +int +find_min(Sequence *s) +{ SeqList *l; + Element *e; + + if (s->minel < 0) + { s->minel = INT_MAX; + for (e = s->frst; e; e = e->nxt) + { if (e->status & 512) + { continue; + } + e->status |= 512; + + if (e->n->ntyp == ATOMIC + || e->n->ntyp == NON_ATOMIC + || e->n->ntyp == D_STEP) + { int n = find_min(e->n->sl->this); + if (n < s->minel) + { s->minel = n; + } + } else if (e->Seqno < s->minel) + { s->minel = e->Seqno; + } + for (l = e->sub; l; l = l->nxt) + { int n = find_min(l->this); + if (n < s->minel) + { s->minel = n; + } } } + } + if (s->minel < globmin) + { globmin = s->minel; + } + return s->minel; +} + +int +find_max(Sequence *s) +{ + if (s->last->Seqno > globmax) + { globmax = s->last->Seqno; + } + return s->last->Seqno; +} + void match_trail(void) { int i, a, nst; Element *dothis; char snap[512], *q; + if (has_code) + { printf("spin: important:\n"); + printf(" =======================================warning====\n"); + printf(" this model contains embedded c code statements\n"); + printf(" these statements will not be executed when the trail\n"); + printf(" is replayed in this way -- they are just printed,\n"); + printf(" which will likely lead to inaccurate variable values.\n"); + printf(" for an accurate replay use: ./pan -r\n"); + printf(" =======================================warning====\n\n"); + } + /* * if source model name is leader.pml * look for the trail file under these names: @@ -88,10 +145,18 @@ match_trail(void) * leader.tra */ - if (ntrail) - sprintf(snap, "%s%d.trail", oFname->name, ntrail); - else - sprintf(snap, "%s.trail", oFname->name); + if (trailfilename) + { if (strlen(*trailfilename) < sizeof(snap)) + { strcpy(snap, (const char *) *trailfilename); + } else + { fatal("filename %s too long", *trailfilename); + } + } else + { if (ntrail) + sprintf(snap, "%s%d.trail", oFname->name, ntrail); + else + sprintf(snap, "%s.trail", oFname->name); + } if ((fd = fopen(snap, "r")) == NULL) { snap[strlen(snap)-2] = '\0'; /* .tra */ @@ -118,9 +183,9 @@ match_trail(void) } } okay: if (xspin == 0 && newer(oFname->name, snap)) - printf("spin: warning, \"%s\" is newer than %s\n", - oFname->name, snap); - + { printf("spin: warning, \"%s\" is newer than %s\n", + oFname->name, snap); + } Tval = 1; /* @@ -132,10 +197,23 @@ okay: hookup(); while (fscanf(fd, "%d:%d:%d\n", &depth, &pno, &nst) == 3) - { if (depth == -2) { start_claim(pno); continue; } - if (depth == -4) { merger = 1; ana_src(0, 1); continue; } - if (depth == -1) + { if (depth == -2) { if (verbose) + { printf("starting claim %d\n", pno); + } + start_claim(pno); + continue; + } + if (depth == -4) + { if (verbose) + { printf("using statement merging\n"); + } + merger = 1; + ana_src(0, 1); + continue; + } + if (depth == -1) + { if (1 || verbose) { if (columns == 2) dotag(stdout, " CYCLE>\n"); else @@ -188,16 +266,50 @@ okay: pno - Have_claim, i, nst, dothis->n->ntyp); lost_trail(); } + + if (0 && !xspin && (verbose&32)) + { printf("step %d i=%d pno %d stmnt %d\n", depth, i, pno, nst); + } + for (X = run; X; X = X->nxt) { if (--i == pno) break; } + if (!X) - { printf("%3d: no process %d ", depth, pno - Have_claim); - printf("(state %d)\n", nst); - lost_trail(); + { if (verbose&32) + { printf("%3d: no process %d (stmnt %d)\n", depth, pno - Have_claim, nst); + printf(" max %d (%d - %d + %d) claim %d ", + nproc - nstop + Skip_claim, + nproc, nstop, Skip_claim, Have_claim); + printf("active processes:\n"); + for (X = run; X; X = X->nxt) + { printf("\tpid %d\tproctype %s\n", X->pid, X->n->name); + } + printf("\n"); + continue; + } else + { printf("%3d:\tproc %d (?) ", depth, pno); + lost_trail(); + } + } else + { int min_seq = find_min(X->ps); + int max_seq = find_max(X->ps); + + + if (nst < min_seq || nst > max_seq) + { printf("%3d: error: invalid statement", depth); + if (verbose&32) + { printf(": pid %d:%d (%s:%d:%d) stmnt %d (valid range %d .. %d)", + pno, X->pid, X->n->name, X->tn, X->b, nst, min_seq, max_seq); + } + printf("\n"); + continue; + /* lost_trail(); */ + } + X->pc = dothis; } - X->pc = dothis; + lineno = dothis->n->ln; Fname = dothis->n->fn; @@ -271,7 +383,7 @@ keepgoing: if (dothis->merge_start) } } if (Have_claim && X && X->pid == 0 - && dothis && dothis->n + && dothis->n && lastclaim != dothis->n->ln) { lastclaim = dothis->n->ln; if (columns == 2) diff --git a/sys/src/cmd/spin/main.c b/sys/src/cmd/spin/main.c index d70164424..d9b3e5bfd 100644 --- a/sys/src/cmd/spin/main.c +++ b/sys/src/cmd/spin/main.c @@ -1,25 +1,23 @@ /***** spin: main.c *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #include +#include #include "spin.h" #include "version.h" +#include +#include #include -/* #include */ #include #ifdef PC -#include -extern int unlink(const char *); + #include #else -#include + #include #endif #include "y.tab.h" @@ -29,6 +27,12 @@ extern Symbol *context; extern char *claimproc; extern void repro_src(void); extern void qhide(int); +extern char CurScope[MAXSCOPESZ]; +extern short has_provided, has_code, has_ltl, has_accept; +extern int realread, buzzed; + +static void add_comptime(char *); +static void add_runtime(char *); Symbol *Fname, *oFname; @@ -40,12 +44,19 @@ 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 norecompile; /* main.c */ +int old_scope_rules; /* use pre 5.3.0 rules */ +int old_priority_rules; /* use pre 6.2.0 rules */ +int product, Strict; +short replay; -int dataflow = 1, merger = 1, deadvar = 1, ccache = 1; +int merger = 1, deadvar = 1, implied_semis = 1; +int ccache = 0; /* oyvind teig: 5.2.0 case caching off by default */ -static int preprocessonly, SeedUsed; +static int preprocessonly, SeedUsed, itsr, itsr_n; +static int seedy; /* be verbose about chosen seed */ +static int inlineonly; /* show inlined code */ +static int dataflow = 1; #if 0 meaning of flags on verbose: @@ -61,99 +72,515 @@ meaning of flags on verbose: static char Operator[] = "operator: "; static char Keyword[] = "keyword: "; static char Function[] = "function-name: "; -static char **add_ltl = (char **)0; -static char **ltl_file = (char **)0; -static char **nvr_file = (char **)0; +static char **add_ltl = (char **) 0; +static char **ltl_file = (char **) 0; +static char **nvr_file = (char **) 0; +static char *ltl_claims = (char *) 0; +static char *pan_runtime = ""; +static char *pan_comptime = ""; +static char formula[4096]; +static FILE *fd_ltl = (FILE *) 0; static char *PreArg[64]; static int PreCnt = 0; static char out1[64]; -static void explain(int); -#ifndef CPP - /* OS2: "spin -Picc -E/Pd+ -E/Q+" */ - /* Visual C++: "spin -PCL -E/E */ -#ifdef PC -#define CPP "gcc -E -x c" /* most systems have gcc anyway */ - /* else use "cpp" */ -#else -#ifdef SOLARIS -#define CPP "/usr/ccs/lib/cpp" -#else -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) -#define CPP "cpp" -#else -#define CPP "/bin/cpp" /* classic Unix systems */ -#endif -#endif -#endif +char **trailfilename; /* new option 'k' */ -#endif -static char *PreProc = CPP; +void explain(int); + +#define CPP "/bin/cpp" /* sometimes: "/lib/cpp" */ + +static char PreProc[512]; extern int depth; /* at least some steps were made */ -void -alldone(int estatus) +int +WhatSeed(void) { - 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", - estatus); - else - printf("Exit-Status 0\n"); - } - exit(estatus); + return SeedUsed; } void -preprocess(char *a, char *b, int a_tmp) -{ char precmd[512], cmd[1024]; int i; -#ifdef PC - extern int try_zpp(char *, char *); - if (PreCnt == 0 && try_zpp(a, b)) goto out; +final_fiddle(void) +{ char *has_a, *has_l, *has_f; + + /* no -a or -l but has_accept: add -a */ + /* no -a or -l in pan_runtime: add -DSAFETY to pan_comptime */ + /* -a or -l but no -f then add -DNOFAIR */ + + has_a = strstr(pan_runtime, "-a"); + has_l = strstr(pan_runtime, "-l"); + has_f = strstr(pan_runtime, "-f"); + + if (!has_l && !has_a && strstr(pan_comptime, "-DNP")) + { add_runtime("-l"); + has_l = strstr(pan_runtime, "-l"); + } + + if (!has_a && !has_l + && !strstr(pan_comptime, "-DSAFETY")) + { if (has_accept + && !strstr(pan_comptime, "-DBFS") + && !strstr(pan_comptime, "-DNOCLAIM")) + { add_runtime("-a"); + has_a = pan_runtime; + } else + { add_comptime("-DSAFETY"); + } } + + if ((has_a || has_l) && !has_f + && !strstr(pan_comptime, "-DNOFAIR")) + { add_comptime("-DNOFAIR"); + } +} + +static int +change_param(char *t, char *what, int range, int bottom) +{ char *ptr; + int v; + + assert(range < 1000 && range > 0); + if ((ptr = strstr(t, what)) != NULL) + { ptr += strlen(what); + if (!isdigit((int) *ptr)) + { return 0; + } + v = atoi(ptr) + 1; /* was: v = (atoi(ptr)+1)%range */ + if (v >= range) + { v = bottom; + } + if (v >= 100) + { *ptr++ = '0' + (v/100); v %= 100; + *ptr++ = '0' + (v/10); + *ptr = '0' + (v%10); + } else if (v >= 10) + { *ptr++ = '0' + (v/10); + *ptr++ = '0' + (v%10); + *ptr = ' '; + } else + { *ptr++ = '0' + v; + *ptr++ = ' '; + *ptr = ' '; + } } + return 1; +} + +static void +change_rs(char *t) +{ char *ptr; + int cnt = 0; + long v; + + if ((ptr = strstr(t, "-RS")) != NULL) + { ptr += 3; + /* room for at least 10 digits */ + v = Rand()%1000000000L; + while (v/10 > 0) + { *ptr++ = '0' + v%10; + v /= 10; + cnt++; + } + *ptr++ = '0' + v; + cnt++; + while (cnt++ < 10) + { *ptr++ = ' '; + } } +} + +int +omit_str(char *in, char *s) +{ char *ptr = strstr(in, s); + int i, nr = -1; + + if (ptr) + { for (i = 0; i < (int) strlen(s); i++) + { *ptr++ = ' '; + } + if (isdigit((int) *ptr)) + { nr = atoi(ptr); + while (isdigit((int) *ptr)) + { *ptr++ = ' '; + } } } + return nr; +} + +void +string_trim(char *t) +{ int n = strlen(t) - 1; + + while (n > 0 && t[n] == ' ') + { t[n--] = '\0'; + } +} + +int +e_system(int v, const char *s) +{ static int count = 1; + /* v == 0 : checks to find non-linked version of gcc */ + /* v == 1 : all other commands */ + /* v == 2 : preprocessing the promela input */ + + if (v == 1) + { if (verbose&(32|64)) /* -v or -w */ + { printf("cmd%02d: %s\n", count++, s); + fflush(stdout); + } + if (verbose&64) /* only -w */ + { return 0; /* suppress the call to system(s) */ + } } + return system(s); +} + +void +alldone(int estatus) +{ char *ptr; +#if defined(WIN32) || defined(WIN64) + struct _stat x; +#else + struct stat x; #endif + if (preprocessonly == 0 && strlen(out1) > 0) + { (void) unlink((const char *) out1); + } + + (void) unlink(TMP_FILE1); + (void) unlink(TMP_FILE2); + + if (!buzzed && seedy && !analyze && !export_ast + && !s_trail && !preprocessonly && depth > 0) + { printf("seed used: %d\n", SeedUsed); + } + + if (!buzzed && xspin && (analyze || s_trail)) + { if (estatus) + { printf("spin: %d error(s) - aborting\n", + estatus); + } else + { printf("Exit-Status 0\n"); + } } + + if (buzzed && replay && !has_code && !estatus) + { extern QH *qh; + QH *j; + int i; + char *tmp = (char *) emalloc(strlen("spin -t") + + strlen(pan_runtime) + strlen(Fname->name) + 8); + pan_runtime = (char *) emalloc(2048); /* more than enough */ + sprintf(pan_runtime, "-n%d ", SeedUsed); + if (jumpsteps) + { sprintf(&pan_runtime[strlen(pan_runtime)], "-j%d ", jumpsteps); + } + if (trailfilename) + { sprintf(&pan_runtime[strlen(pan_runtime)], "-k%s ", *trailfilename); + } + if (cutoff) + { sprintf(&pan_runtime[strlen(pan_runtime)], "-u%d ", cutoff); + } + for (i = 1; i <= PreCnt; i++) + { strcat(pan_runtime, PreArg[i]); + strcat(pan_runtime, " "); + } + for (j = qh; j; j = j->nxt) + { sprintf(&pan_runtime[strlen(pan_runtime)], "-q%d ", j->n); + } + if (strcmp(PreProc, CPP) != 0) + { sprintf(&pan_runtime[strlen(pan_runtime)], "\"-P%s\" ", PreProc); + } + /* -oN options 1..5 are ignored in simulations */ + if (old_priority_rules) strcat(pan_runtime, "-o6 "); + if (!implied_semis) strcat(pan_runtime, "-o7 "); + if (no_print) strcat(pan_runtime, "-b "); + if (no_wrapup) strcat(pan_runtime, "-B "); + if (columns == 1) strcat(pan_runtime, "-c "); + if (columns == 2) strcat(pan_runtime, "-M "); + if (seedy == 1) strcat(pan_runtime, "-h "); + if (like_java == 1) strcat(pan_runtime, "-J "); + if (old_scope_rules) strcat(pan_runtime, "-O "); + if (notabs) strcat(pan_runtime, "-T "); + if (verbose&1) strcat(pan_runtime, "-g "); + if (verbose&2) strcat(pan_runtime, "-l "); + if (verbose&4) strcat(pan_runtime, "-p "); + if (verbose&8) strcat(pan_runtime, "-r "); + if (verbose&16) strcat(pan_runtime, "-s "); + if (verbose&32) strcat(pan_runtime, "-v "); + if (verbose&64) strcat(pan_runtime, "-w "); + if (m_loss) strcat(pan_runtime, "-m "); + sprintf(tmp, "spin -t %s %s", pan_runtime, Fname->name); + estatus = e_system(1, tmp); /* replay */ + exit(estatus); /* replay without c_code */ + } + + if (buzzed && (!replay || has_code) && !estatus) + { char *tmp, *tmp2 = NULL, *P_X; + char *C_X = (buzzed == 2) ? "-O" : ""; + + if (replay && strlen(pan_comptime) == 0) + { +#if defined(WIN32) || defined(WIN64) + P_X = "pan"; +#else + P_X = "./pan"; +#endif + if (stat(P_X, (struct stat *)&x) < 0) + { goto recompile; /* no executable pan for replay */ + } + tmp = (char *) emalloc(8 + strlen(P_X) + strlen(pan_runtime) +4); + /* the final +4 is too allow adding " &" in some cases */ + sprintf(tmp, "%s %s", P_X, pan_runtime); + goto runit; + } +#if defined(WIN32) || defined(WIN64) + P_X = "-o pan pan.c && pan"; +#else + P_X = "-o pan pan.c && ./pan"; +#endif + /* swarm and biterate randomization additions */ + if (!replay && itsr) /* iterative search refinement */ + { if (!strstr(pan_comptime, "-DBITSTATE")) + { add_comptime("-DBITSTATE"); + } + if (!strstr(pan_comptime, "-DPUTPID")) + { add_comptime("-DPUTPID"); + } + if (!strstr(pan_comptime, "-DT_RAND") + && !strstr(pan_comptime, "-DT_REVERSE")) + { add_runtime("-T0 "); /* controls t_reverse */ + } + if (!strstr(pan_runtime, "-P") /* runtime flag */ + || pan_runtime[2] < '0' + || pan_runtime[2] > '1') /* no -P0 or -P1 */ + { add_runtime("-P0 "); /* controls p_reverse */ + } + if (!strstr(pan_runtime, "-w")) + { add_runtime("-w18 "); /* -w18 = 256K */ + } else + { char nv[32]; + int x; + x = omit_str(pan_runtime, "-w"); + if (x >= 0) + { sprintf(nv, "-w%d ", x); + add_runtime(nv); /* added spaces */ + } } + if (!strstr(pan_runtime, "-h")) + { add_runtime("-h0 "); /* 0..499 */ + /* leave 2 spaces for increments up to -h499 */ + } else if (!strstr(pan_runtime, "-hash")) + { char nv[32]; + int x; + x = omit_str(pan_runtime, "-h"); + if (x >= 0) + { sprintf(nv, "-h%d ", x%500); + add_runtime(nv); /* added spaces */ + } } + if (!strstr(pan_runtime, "-k")) + { add_runtime("-k1 "); /* 1..3 */ + } else + { char nv[32]; + int x; + x = omit_str(pan_runtime, "-k"); + if (x >= 0) + { sprintf(nv, "-k%d ", x%4); + add_runtime(nv); /* added spaces */ + } } + if (strstr(pan_runtime, "-p_rotate")) + { char nv[32]; + int x; + x = omit_str(pan_runtime, "-p_rotate"); + if (x < 0) + { x = 0; + } + sprintf(nv, "-p_rotate%d ", x%256); + add_runtime(nv); /* added spaces */ + } else if (strstr(pan_runtime, "-p_permute") == 0) + { add_runtime("-p_rotate0 "); + } + if (strstr(pan_runtime, "-RS")) + { (void) omit_str(pan_runtime, "-RS"); + } + /* need room for at least 10 digits */ + add_runtime("-RS1234567890 "); + change_rs(pan_runtime); + } +recompile: + if (strstr(PreProc, "cpp")) /* unix/linux */ + { strcpy(PreProc, "gcc"); /* need compiler */ + } else if ((tmp = strstr(PreProc, "-E")) != NULL) + { *tmp = '\0'; /* strip preprocessing flags */ + } + + final_fiddle(); + tmp = (char *) emalloc(8 + /* account for alignment */ + strlen(PreProc) + + strlen(C_X) + + strlen(pan_comptime) + + strlen(P_X) + + strlen(pan_runtime) + + strlen(" -p_reverse & ")); + tmp2 = tmp; + + /* P_X ends with " && ./pan " */ + sprintf(tmp, "%s %s %s %s %s", + PreProc, C_X, pan_comptime, P_X, pan_runtime); + + if (!replay) + { if (itsr < 0) /* swarm only */ + { strcat(tmp, " &"); /* after ./pan */ + itsr = -itsr; /* now same as biterate */ + } + /* do compilation first + * split cc command from run command + * leave cc in tmp, and set tmp2 to run + */ + if ((ptr = strstr(tmp, " && ")) != NULL) + { tmp2 = ptr + 4; /* first run */ + *ptr = '\0'; + } } + + if (has_ltl) + { (void) unlink("_spin_nvr.tmp"); + } + if (!norecompile) + { +#ifdef PC + /* make sure that if compilation fails we do not continue */ + (void) unlink("./pan.exe"); +#else + (void) unlink("./pan"); +#endif + } +runit: + if (norecompile && tmp != tmp2) + { estatus = 0; + } else + { if (itsr > 0) /* else it happens below */ + { estatus = e_system(1, tmp); /* compile or run */ + } } + if (replay || estatus < 0) + { goto skipahead; + } + /* !replay */ + if (itsr == 0) /* single run */ + { estatus = e_system(1, tmp2); + } else if (itsr > 0) /* iterative search refinement */ + { int is_swarm = 0; + if (tmp2 != tmp) /* swarm: did only compilation so far */ + { tmp = tmp2; /* now we point to the run command */ + estatus = e_system(1, tmp); /* first run */ + } + itsr--; /* count down */ + + /* the following are added back randomly later */ + (void) omit_str(tmp, "-p_reverse"); /* replaced by spaces */ + (void) omit_str(tmp, "-p_normal"); + + if (strstr(tmp, " &") != NULL) + { (void) omit_str(tmp, " &"); + is_swarm = 1; + } + + /* increase -w every itsr_n-th run */ + if ((itsr_n > 0 && (itsr == 0 || (itsr%itsr_n) != 0)) + || (change_param(tmp, "-w", 36, 18) >= 0)) /* max 4G bit statespace */ + { (void) change_param(tmp, "-h", 500, 0); /* hash function 0.499 */ + (void) change_param(tmp, "-p_rotate", 256, 0); /* if defined */ + (void) change_param(tmp, "-k", 4, 1); /* nr bits per state 0->1,2,3 */ + (void) change_param(tmp, "-T", 2, 0); /* with or without t_reverse*/ + (void) change_param(tmp, "-P", 2, 0); /* -P 0..1 != p_reverse */ + change_rs(tmp); /* change random seed */ + string_trim(tmp); + if (rand()%5 == 0) /* 20% of all runs */ + { strcat(tmp, " -p_reverse "); + /* at end, so this overrides -p_rotateN, if there */ + /* but -P0..1 disable this in 50% of the cases */ + /* so its really activated in 10% of all runs */ + } else if (rand()%6 == 0) /* override p_rotate and p_reverse */ + { strcat(tmp, " -p_normal "); + } + if (is_swarm) + { strcat(tmp, " &"); + } + goto runit; + } } +skipahead: + (void) unlink("pan.b"); + (void) unlink("pan.c"); + (void) unlink("pan.h"); + (void) unlink("pan.m"); + (void) unlink("pan.p"); + (void) unlink("pan.t"); + } + exit(estatus); +} +#if 0 + -P0 normal active process creation + -P1 reversed order for *active* process creation != p_reverse + + -T0 normal transition exploration + -T1 reversed order of transition exploration + + -DP_RAND (random starting point +- -DP_REVERSE) + -DPERMUTED (also enables -p_rotateN and -p_reverse) + -DP_REVERSE (same as -DPERMUTED with -p_reverse, but 7% faster) + + -DT_RAND (random starting point -- optionally with -T0..1) + -DT_REVERSE (superseded by -T0..1 options) + + -hash generates new hash polynomial for -h0 + + permutation modes: + -permuted (adds -DPERMUTED) -- this is also the default with -swarm + -t_reverse (same as -T1) + -p_reverse (similar to -P1) + -p_rotateN + -p_normal + + less useful would be (since there is less non-determinism in transitions): + -t_rotateN -- a controlled version of -DT_RAND + + compiling with -DPERMUTED enables a number of new runtime options, + that -swarmN,M will also exploit: + -p_permute (default) + -p_rotateN + -p_reverse +#endif + +void +preprocess(char *a, char *b, int a_tmp) +{ char precmd[1024], cmd[2048]; + int i; +#ifdef PC + /* gcc is sometimes a symbolic link to gcc-4 + that does not work well in cygwin, so we try + to use the actual executable that is used. + the code below assumes we are on a cygwin-like system + */ + if (strncmp(PreProc, "gcc ", strlen("gcc ")) == 0) + { if (e_system(0, "gcc-4 --version > pan.pre") == 0) + { strcpy(PreProc, "gcc-4 -std=gnu99 -E -x c"); + } else if (e_system(0, "gcc-3 --version > pan.pre") == 0) + { strcpy(PreProc, "gcc-3 -std=gnu99 -E -x c"); + } } +#endif + + assert(strlen(PreProc) < sizeof(precmd)); strcpy(precmd, PreProc); for (i = 1; i <= PreCnt; i++) { strcat(precmd, " "); strcat(precmd, PreArg[i]); } + if (strlen(precmd) > sizeof(precmd)) + { fprintf(stdout, "spin: too many -D args, aborting\n"); + alldone(1); + } sprintf(cmd, "%s %s > %s", precmd, a, b); - if (system((const char *)cmd)) + if (e_system(2, (const char *)cmd)) /* preprocessing */ { (void) unlink((const char *) b); if (a_tmp) (void) unlink((const char *) a); fprintf(stdout, "spin: preprocessing failed\n"); /* 4.1.2 was stderr */ alldone(1); /* no return, error exit */ } -#ifdef PC -out: -#endif if (a_tmp) (void) unlink((const char *) a); } -FILE * -cpyfile(char *src, char *tgt) -{ FILE *inp, *out; - char buf[1024]; - - inp = fopen(src, "r"); - out = fopen(tgt, "w"); - if (!inp || !out) - { printf("spin: cannot cp %s to %s\n", src, tgt); - alldone(1); - } - while (fgets(buf, 1024, inp)) - fprintf(out, "%s", buf); - fclose(inp); - return out; -} - void usage(void) { @@ -168,33 +595,73 @@ usage(void) printf("\t-d produce symbol-table information\n"); printf("\t-Dyyy pass -Dyyy to the preprocessor\n"); printf("\t-Eyyy pass yyy to the preprocessor\n"); + printf("\t-e compute synchronous product of multiple never claims (modified by -L)\n"); printf("\t-f \"..formula..\" translate LTL "); printf("into never claim\n"); - printf("\t-F file like -f, but with the LTL "); - printf("formula stored in a 1-line file\n"); + printf("\t-F file like -f, but with the LTL 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-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"); + printf("\t-k fname use the trailfile stored in file fname, see also -t\n"); + printf("\t-L when using -e, use strict language intersection\n"); printf("\t-l print all local variables\n"); - printf("\t-M print msc-flow in Postscript\n"); + printf("\t-M generate msc-flow in tcl/tk format\n"); printf("\t-m lose msgs sent to full queues\n"); - printf("\t-N file use never claim stored in file\n"); + printf("\t-N fname use never claim stored in file fname\n"); printf("\t-nN seed for random nr generator\n"); + printf("\t-O use old scope rules (pre 5.3.0)\n"); printf("\t-o1 turn off dataflow-optimizations 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-o4 turn on rendezvous optiomizations in verifier\n"); + printf("\t-o5 turn on case caching (reduces size of pan.m, but affects reachability reports)\n"); + printf("\t-o6 revert to the old rules for interpreting priority tags (pre version 6.2)\n"); + printf("\t-o7 revert to the old rules for semi-colon usage (pre version 6.3)\n"); printf("\t-Pxxx use xxx for preprocessing\n"); printf("\t-p print all statements\n"); + printf("\t-pp pretty-print (reformat) stdin, write stdout\n"); printf("\t-qN suppress io for queue N in printouts\n"); printf("\t-r print receive events\n"); + printf("\t-replay replay an error trail-file found earlier\n"); + printf("\t if the model contains embedded c-code, the ./pan executable is used\n"); + printf("\t otherwise spin itself is used to replay the trailfile\n"); + printf("\t note that pan recognizes different runtime options than spin itself\n"); + printf("\t-search (or -run) generate a verifier, and compile and run it\n"); + printf("\t options before -search are interpreted by spin to parse the input\n"); + printf("\t options following a -search are used to compile and run the verifier pan\n"); + printf("\t valid options that can follow a -search argument include:\n"); + printf("\t -bfs perform a breadth-first search\n"); + printf("\t -bfspar perform a parallel breadth-first search\n"); + printf("\t -bcs use the bounded-context-switching algorithm\n"); + printf("\t -bitstate or -bit, use bitstate storage\n"); + printf("\t -biterate use bitstate with iterative search refinement (-w18..-w35)\n"); + printf("\t -swarmN,M like -biterate, but running all iterations in parallel\n"); + printf("\t perform N parallel runs and increment -w every M runs\n"); + printf("\t default value for N is 10, default for M is 1\n"); + printf("\t (add -w to see which commands will be executed)\n"); + printf("\t (add -W if ./pan exists and need not be recompiled)\n"); + printf("\t -link file.c link executable pan to file.c\n"); + printf("\t -collapse use collapse state compression\n"); + printf("\t -hc use hash-compact storage\n"); + printf("\t -noclaim ignore all ltl and never claims\n"); + printf("\t -p_permute use process scheduling order random permutation\n"); + printf("\t -p_rotateN use process scheduling order rotation by N\n"); + printf("\t -p_reverse use process scheduling order reversal\n"); + printf("\t -ltl p verify the ltl property named p\n"); + printf("\t -safety compile for safety properties only\n"); + printf("\t -i use the dfs iterative shortening algorithm\n"); + printf("\t -a search for acceptance cycles\n"); + printf("\t -l search for non-progress cycles\n"); + printf("\t similarly, a -D... parameter can be specified to modify the compilation\n"); + printf("\t and any valid runtime pan argument can be specified for the verification\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-t[N] follow [Nth] simulation trail, see also -k\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"); @@ -204,8 +671,8 @@ usage(void) alldone(1); } -void -optimizations(char nr) +int +optimizations(int nr) { switch (nr) { case '1': @@ -243,37 +710,114 @@ optimizations(char nr) printf("spin: case caching turned %s\n", ccache?"on":"off"); break; + case '6': + old_priority_rules = 1; + if (verbose&32) + printf("spin: using old priority rules (pre version 6.2)\n"); + return 0; /* no break */ + case '7': + implied_semis = 0; + if (verbose&32) + printf("spin: no implied semi-colons (pre version 6.3)\n"); + return 0; /* no break */ default: printf("spin: bad or missing parameter on -o\n"); usage(); break; } + return 1; } -#if 0 -static int -Rename(const char *old, char *new) -{ FILE *fo, *fn; - char buf[1024]; +static void +add_comptime(char *s) +{ char *tmp; - if ((fo = fopen(old, "r")) == NULL) - { printf("spin: cannot open %s\n", old); - return 1; + if (!s || strstr(pan_comptime, s)) + { return; } - 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 */ + tmp = (char *) emalloc(strlen(pan_comptime)+strlen(s)+2); + sprintf(tmp, "%s %s", pan_comptime, s); + pan_comptime = tmp; +} + +static struct { + char *ifsee, *thendo; + int keeparg; +} pats[] = { + { "-bfspar", "-DBFS_PAR", 0 }, + { "-bfs", "-DBFS", 0 }, + { "-bcs", "-DBCS", 0 }, + { "-bitstate", "-DBITSTATE", 0 }, + { "-bit", "-DBITSTATE", 0 }, + { "-hc", "-DHC4", 0 }, + { "-collapse", "-DCOLLAPSE", 0 }, + { "-noclaim", "-DNOCLAIM", 0 }, + { "-permuted", "-DPERMUTED", 0 }, + { "-p_permute", "-DPERMUTED", 1 }, + { "-p_rotate", "-DPERMUTED", 1 }, + { "-p_reverse", "-DPERMUTED", 1 }, + { "-safety", "-DSAFETY", 0 }, + { "-i", "-DREACH", 1 }, + { "-l", "-DNP", 1 }, + { 0, 0 } +}; + +static void +set_itsr_n(char *s) /* e.g., -swarm12,3 */ +{ char *tmp; + + if ((tmp = strchr(s, ',')) != NULL) + { tmp++; + if (*tmp != '\0' && isdigit((int) *tmp)) + { itsr_n = atoi(tmp); + if (itsr_n < 2) + { itsr_n = 0; + } } } +} + +static void +add_runtime(char *s) +{ char *tmp; + int i; + + if (strncmp(s, "-biterate", strlen("-biterate")) == 0) + { itsr = 10; /* default nr of sequential iterations */ + if (isdigit((int) s[9])) + { itsr = atoi(&s[9]); + if (itsr < 1) + { itsr = 1; + } + set_itsr_n(s); + } + return; + } + if (strncmp(s, "-swarm", strlen("-swarm")) == 0) + { itsr = -10; /* parallel iterations */ + if (isdigit((int) s[6])) + { itsr = atoi(&s[6]); + if (itsr < 1) + { itsr = 1; + } + itsr = -itsr; + set_itsr_n(s); + } + return; + } + + for (i = 0; pats[i].ifsee; i++) + { if (strncmp(s, pats[i].ifsee, strlen(pats[i].ifsee)) == 0) + { add_comptime(pats[i].thendo); + if (pats[i].keeparg) + { break; + } + return; + } } + + tmp = (char *) emalloc(strlen(pan_runtime)+strlen(s)+2); + sprintf(tmp, "%s %s", pan_runtime, s); + pan_runtime = tmp; } -#endif int main(int argc, char *argv[]) @@ -285,17 +829,16 @@ main(int argc, char *argv[]) yyin = stdin; yyout = stdout; tl_out = stdout; + strcpy(CurScope, "_"); - /* unused flags: e, w, x, y, z, A, G, I, L, O, Q, R, S, T, W */ + assert(strlen(CPP) < sizeof(PreProc)); + strcpy(PreProc, CPP); + + /* unused flags: y, z, G, L, Q, R, W */ while (argc > 1 && argv[1][0] == '-') { switch (argv[1][1]) { - - /* 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 'a': analyze = 1; break; case 'B': no_wrapup = 1; break; case 'b': no_print = 1; break; case 'C': Caccess = 1; break; @@ -305,6 +848,7 @@ main(int argc, char *argv[]) case 'd': dumptab = 1; break; case 'E': PreArg[++PreCnt] = (char *) &argv[1][2]; break; + case 'e': product++; break; /* see also 'L' */ case 'F': ltl_file = (char **) (argv+2); argc--; argv++; break; case 'f': add_ltl = (char **) argv; @@ -315,34 +859,110 @@ main(int argc, char *argv[]) case 'I': inlineonly = 1; break; case 'J': like_java = 1; break; case 'j': jumpsteps = atoi(&argv[1][2]); break; + case 'k': s_trail = 1; + trailfilename = (char **) (argv+2); + argc--; argv++; break; + case 'L': Strict++; break; /* modified -e */ case 'l': verbose += 2; break; case 'M': columns = 2; break; case 'm': m_loss = 1; break; case 'N': nvr_file = (char **) (argv+2); argc--; argv++; break; case 'n': T = atoi(&argv[1][2]); tl_terse = 1; break; - case 'o': optimizations(argv[1][2]); - usedopts = 1; break; - case 'P': PreProc = (char *) &argv[1][2]; break; - case 'p': verbose += 4; break; - case 'q': if (isdigit(argv[1][2])) + case 'O': old_scope_rules = 1; break; + case 'o': usedopts += optimizations(argv[1][2]); break; + case 'P': assert(strlen((const char *) &argv[1][2]) < sizeof(PreProc)); + strcpy(PreProc, (const char *) &argv[1][2]); + break; + case 'p': if (argv[1][2] == 'p') + { pretty_print(); + alldone(0); + } + verbose += 4; break; + case 'q': if (isdigit((int) argv[1][2])) qhide(atoi(&argv[1][2])); break; - case 'r': verbose += 8; break; - case 's': verbose += 16; break; + case 'r': + if (strcmp(&argv[1][1], "run") == 0) + { Srand((unsigned int) T); +samecase: if (buzzed != 0) + { fatal("cannot combine -x with -run -replay or -search", (char *)0); + } + buzzed = 2; + analyze = 1; + argc--; argv++; + /* process all remaining arguments as relating to pan: */ + while (argc > 1 && argv[1][0] == '-') + { switch (argv[1][1]) { + case 'D': /* eg -DNP */ + /* case 'E': conflicts with runtime arg */ + case 'O': /* eg -O2 */ + case 'U': /* to undefine a macro */ + add_comptime(argv[1]); + break; + case 'l': + if (strcmp(&argv[1][1], "ltl") == 0) + { add_runtime("-N"); + argc--; argv++; + add_runtime(argv[1]); /* prop name */ + break; + } + if (strcmp(&argv[1][1], "link") == 0) + { argc--; argv++; + add_comptime(argv[1]); + break; + } + /* else fall through */ + default: + add_runtime(argv[1]); /* -bfs etc. */ + break; + } + argc--; argv++; + } + argc++; argv--; + } else if (strcmp(&argv[1][1], "replay") == 0) + { replay = 1; + add_runtime("-r"); + goto samecase; + } else + { verbose += 8; + } + break; + case 'S': separate = atoi(&argv[1][2]); /* S1 or S2 */ + /* generate code for separate compilation */ + analyze = 1; break; + case 's': + if (strcmp(&argv[1][1], "simulate") == 0) + { break; /* ignore */ + } + if (strcmp(&argv[1][1], "search") == 0) + { goto samecase; + } + verbose += 16; break; case 'T': notabs = 1; break; case 't': s_trail = 1; - if (isdigit(argv[1][2])) - ntrail = atoi(&argv[1][2]); + if (isdigit((int)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 'u': cutoff = atoi(&argv[1][2]); break; case 'v': verbose += 32; break; - case 'V': printf("%s\n", Version); + case 'V': printf("%s\n", SpinVersion); alldone(0); break; case 'w': verbose += 64; break; + case 'W': norecompile = 1; break; /* 6.4.7: for swarm/biterate */ + case 'x': /* internal - reserved use */ + if (buzzed != 0) + { fatal("cannot combine -x with -run -search or -replay", (char *)0); + } + buzzed = 1; /* implies also -a -o3 */ + pan_runtime = "-d"; + analyze = 1; + usedopts += optimizations('3'); + break; case 'X': xspin = notabs = 1; #ifndef PC signal(SIGPIPE, alldone); /* not posix... */ @@ -355,65 +975,75 @@ main(int argc, char *argv[]) } argc--; argv++; } + + if (columns == 2 && !cutoff) + { cutoff = 1024; + } + if (usedopts && !analyze) - printf("spin: warning -o[123] option ignored in simulations\n"); - + printf("spin: warning -o[1..5] option ignored in simulations\n"); + if (ltl_file) - { char formula[4096]; - add_ltl = ltl_file-2; add_ltl[1][1] = 'f'; + { add_ltl = ltl_file-2; add_ltl[1][1] = 'f'; if (!(tl_out = fopen(*ltl_file, "r"))) { printf("spin: cannot open %s\n", *ltl_file); alldone(1); } - fgets(formula, 4096, tl_out); + if (!fgets(formula, 4096, tl_out)) + { printf("spin: cannot read %s\n", *ltl_file); + } fclose(tl_out); tl_out = stdout; *ltl_file = (char *) formula; } if (argc > 1) - { char cmd[128], out2[64]; + { FILE *fd = stdout; + char cmd[512], out2[512]; /* must remain in current dir */ strcpy(out1, "pan.pre"); if (add_ltl || nvr_file) - strcpy(out2, "pan.___"); - - if (add_ltl) - { tl_out = cpyfile(argv[1], out2); - nr_errs = tl_main(2, add_ltl); /* in tl_main.c */ - fclose(tl_out); - preprocess(out2, out1, 1); - } else if (nvr_file) - { FILE *fd; char buf[1024]; - - if ((fd = fopen(*nvr_file, "r")) == NULL) - { printf("spin: cannot open %s\n", - *nvr_file); + { assert(strlen(argv[1]) < sizeof(out2)); + sprintf(out2, "%s.nvr", argv[1]); + if ((fd = fopen(out2, MFLAGS)) == NULL) + { printf("spin: cannot create tmp file %s\n", + out2); alldone(1); } - tl_out = cpyfile(argv[1], out2); - while (fgets(buf, 1024, fd)) - fprintf(tl_out, "%s", buf); - fclose(tl_out); + fprintf(fd, "#include \"%s\"\n", argv[1]); + } + + if (add_ltl) + { tl_out = fd; + nr_errs = tl_main(2, add_ltl); + fclose(fd); + preprocess(out2, out1, 1); + } else if (nvr_file) + { fprintf(fd, "#include \"%s\"\n", *nvr_file); fclose(fd); preprocess(out2, out1, 1); } else - preprocess(argv[1], out1, 0); + { preprocess(argv[1], out1, 0); + } if (preprocessonly) - alldone(0); + { alldone(0); + } if (!(yyin = fopen(out1, "r"))) { printf("spin: cannot open %s\n", out1); alldone(1); } - if (strncmp(argv[1], "progress", 8) == 0 - || strncmp(argv[1], "accept", 6) == 0) - sprintf(cmd, "_%s", argv[1]); - else - strcpy(cmd, argv[1]); + assert(strlen(argv[1])+1 < sizeof(cmd)); + + if (strncmp(argv[1], "progress", (size_t) 8) == 0 + || strncmp(argv[1], "accept", (size_t) 6) == 0) + { sprintf(cmd, "_%s", argv[1]); + } else + { strcpy(cmd, argv[1]); + } oFname = Fname = lookup(cmd); if (oFname->name[0] == '\"') { int i = (int) strlen(oFname->name); @@ -428,32 +1058,54 @@ main(int argc, char *argv[]) printf("spin: missing argument to -f\n"); alldone(1); } - printf("%s\n", Version); - printf("reading input from stdin:\n"); + printf("%s\n", SpinVersion); + fprintf(stderr, "spin: error, no filename specified\n"); fflush(stdout); + alldone(1); } if (columns == 2) { extern void putprelude(void); - if (xspin || verbose&(1|4|8|16|32)) + if (xspin || (verbose & (1|4|8|16|32))) { printf("spin: -c precludes all flags except -t\n"); alldone(1); } putprelude(); } if (columns && !(verbose&8) && !(verbose&16)) - verbose += (8+16); + { verbose += (8+16); + } if (columns == 2 && limited_vis) - verbose += (1+4); - Srand(T); /* defined in run.c */ + { verbose += (1+4); + } + + Srand((unsigned int) T); /* defined in run.c */ 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 */ + s = lookup("_priority"); s->type = PREDEF; /* new 6.2.0 */ yyparse(); fclose(yyin); + + if (ltl_claims) + { Symbol *r; + fclose(fd_ltl); + if (!(yyin = fopen(ltl_claims, "r"))) + { fatal("cannot open %s", ltl_claims); + } + r = oFname; + oFname = Fname = lookup(ltl_claims); + lineno = 0; + yyparse(); + fclose(yyin); + oFname = Fname = r; + if (0) + { (void) unlink(ltl_claims); + } } + loose_ends(); if (inlineonly) @@ -463,31 +1115,73 @@ main(int argc, char *argv[]) chanaccess(); if (!Caccess) - { if (!s_trail && (dataflow || merger)) - ana_src(dataflow, merger); + { if (has_provided && merger) + { merger = 0; /* cannot use statement merging in this case */ + } + if (!s_trail && (dataflow || merger) && (!replay || has_code)) + { ana_src(dataflow, merger); + } sched(); alldone(nr_errs); } + return 0; } -int -yywrap(void) /* dummy routine */ +void +ltl_list(char *nm, char *fm) { - return 1; + if (s_trail + || analyze + || dumptab) /* when generating pan.c or replaying a trace */ + { if (!ltl_claims) + { ltl_claims = "_spin_nvr.tmp"; + if ((fd_ltl = fopen(ltl_claims, MFLAGS)) == NULL) + { fatal("cannot open tmp file %s", ltl_claims); + } + tl_out = fd_ltl; + } + + add_ltl = (char **) emalloc(5 * sizeof(char *)); + add_ltl[1] = "-c"; + add_ltl[2] = nm; + add_ltl[3] = "-f"; + add_ltl[4] = (char *) emalloc(strlen(fm)+4); + strcpy(add_ltl[4], "!("); + strcat(add_ltl[4], fm); + strcat(add_ltl[4], ")"); + /* add_ltl[4] = fm; */ + nr_errs += tl_main(4, add_ltl); + + fflush(tl_out); + /* should read this file after the main file is read */ + } } void non_fatal(char *s1, char *s2) -{ extern char yytext[]; +{ extern int yychar; extern char yytext[]; - printf("spin: line %3d %s, Error: ", - lineno, Fname?Fname->name:"nofilename"); + printf("spin: %s:%d, Error: ", + Fname?Fname->name:(oFname?oFname->name:"nofilename"), lineno); +#if 1 + printf(s1, s2); /* avoids a gcc warning */ +#else if (s2) printf(s1, s2); else printf(s1); - if (yytext && strlen(yytext)>1) + if (yychar > 0) + { if (yychar == SEMI) + { printf(" statement separator"); + } else + { printf(" saw '"); + explain(yychar); + printf("'"); + } } +#endif + + if (strlen(yytext)>1) printf(" near '%s'", yytext); printf("\n"); nr_errs++; @@ -497,37 +1191,52 @@ void fatal(char *s1, char *s2) { non_fatal(s1, s2); + (void) unlink("pan.b"); + (void) unlink("pan.c"); + (void) unlink("pan.h"); + (void) unlink("pan.m"); + (void) unlink("pan.t"); + (void) unlink("pan.p"); + (void) unlink("pan.pre"); + if (!(verbose&32)) + { (void) unlink("_spin_nvr.tmp"); + } alldone(1); } char * -emalloc(int n) +emalloc(size_t n) { char *tmp; + static unsigned long cnt = 0; if (n == 0) return NULL; /* robert shelton 10/20/06 */ if (!(tmp = (char *) malloc(n))) + { printf("spin: allocated %ld Gb, wanted %d bytes more\n", + cnt/(1024*1024*1024), (int) n); fatal("not enough memory", (char *)0); + } + cnt += (unsigned long) n; memset(tmp, 0, n); return tmp; } void -trapwonly(Lextok *n, char *unused) -{ extern int realread; - short i = (n->sym)?n->sym->type:0; +trapwonly(Lextok *n /* , char *unused */) +{ short i = (n->sym)?n->sym->type:0; - if (i != MTYPE - && i != BIT - && i != BYTE - && i != SHORT - && i != INT - && i != UNSIGNED) - return; + /* printf("%s realread %d type %d\n", n->sym?n->sym->name:"--", realread, i); */ - if (realread) - n->sym->hidden |= 128; /* var is read at least once */ + if (realread + && (i == MTYPE + || i == BIT + || i == BYTE + || i == SHORT + || i == INT + || i == UNSIGNED)) + { n->sym->hidden |= 128; /* var is read at least once */ + } } void @@ -555,7 +1264,8 @@ nn(Lextok *s, int t, Lextok *ll, Lextok *rl) { Lextok *n = (Lextok *) emalloc(sizeof(Lextok)); static int warn_nn = 0; - n->ntyp = (short) t; + n->uiid = is_inline(); /* record origin of the statement */ + n->ntyp = (unsigned short) t; if (s && s->fn) { n->ln = s->ln; n->fn = s->fn; @@ -679,13 +1389,13 @@ rem_var(Symbol *a, Lextok *b, Symbol *c, Lextok *ndx) #endif } -static void +void explain(int n) { 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; @@ -698,6 +1408,16 @@ explain(int n) case 'R': fprintf(fd, "recv poll %s", Operator); break; case '@': fprintf(fd, "@"); break; case '?': fprintf(fd, "(x->y:z)"); break; +#if 1 + case NEXT: fprintf(fd, "X"); break; + case ALWAYS: fprintf(fd, "[]"); break; + case EVENTUALLY: fprintf(fd, "<>"); break; + case IMPLIES: fprintf(fd, "->"); break; + case EQUIV: fprintf(fd, "<->"); break; + case UNTIL: fprintf(fd, "U"); break; + case WEAK_UNTIL: fprintf(fd, "W"); break; + case IN: fprintf(fd, "%sin", Keyword); break; +#endif case ACTIVE: fprintf(fd, "%sactive", Keyword); break; case AND: fprintf(fd, "%s&&", Operator); break; case ASGN: fprintf(fd, "%s=", Operator); break; @@ -724,6 +1444,7 @@ explain(int n) case FI: fprintf(fd, "%sfi", Keyword); break; case FULL: fprintf(fd, "%sfull", Function); break; case GE: fprintf(fd, "%s>=", Operator); break; + case GET_P: fprintf(fd, "%sget_priority",Function); break; case GOTO: fprintf(fd, "%sgoto", Keyword); break; case GT: fprintf(fd, "%s>", Operator); break; case HIDDEN: fprintf(fd, "%shidden", Keyword); break; @@ -763,6 +1484,8 @@ explain(int n) case RUN: fprintf(fd, "%srun", Operator); break; case SEP: fprintf(fd, "token: ::"); break; case SEMI: fprintf(fd, ";"); break; + case ARROW: fprintf(fd, "->"); break; + case SET_P: fprintf(fd, "%sset_priority",Function); break; case SHOW: fprintf(fd, "%sshow", Keyword); break; case SND: fprintf(fd, "%s!", Operator); break; case STRING: fprintf(fd, "a string"); break; @@ -776,3 +1499,5 @@ explain(int n) case UNLESS: fprintf(fd, "%sunless", Keyword); break; } } + + diff --git a/sys/src/cmd/spin/mesg.c b/sys/src/cmd/spin/mesg.c index 4b2806b40..74e1fe33a 100644 --- a/sys/src/cmd/spin/mesg.c +++ b/sys/src/cmd/spin/mesg.c @@ -1,14 +1,12 @@ /***** spin: mesg.c *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ +#include #include "spin.h" #include "y.tab.h" @@ -24,9 +22,10 @@ extern int lineno, depth, xspin, m_loss, jumpsteps; extern int nproc, nstop; extern short Have_claim; +QH *qh; Queue *qtab = (Queue *) 0; /* linked list of queues */ Queue *ltab[MAXQ]; /* linear list of queues */ -int nqs = 0, firstrow = 1; +int nqs = 0, firstrow = 1, has_stdin = 0; char Buf[4096]; static Lextok *n_rem = (Lextok *) 0; @@ -73,7 +72,7 @@ qmake(Symbol *s) return eval(s->ini); q = (Queue *) emalloc(sizeof(Queue)); - q->qid = ++nqs; + q->qid = (short) ++nqs; q->nslots = s->ini->val; q->nflds = cnt_mpars(s->ini->rgt); q->setat = depth; @@ -130,7 +129,7 @@ qsend(Lextok *n) if (whichq == -1) { printf("Error: sending to an uninitialized chan\n"); - whichq = 0; + /* whichq = 0; */ return 0; } if (whichq < MAXQ && whichq >= 0 && ltab[whichq]) @@ -143,6 +142,37 @@ qsend(Lextok *n) return 0; } +#ifndef PC + #include + static struct termios initial_settings, new_settings; + + void + peek_ch_init(void) + { + tcgetattr(0,&initial_settings); + + new_settings = initial_settings; + new_settings.c_lflag &= ~ICANON; + new_settings.c_lflag &= ~ECHO; + new_settings.c_lflag &= ~ISIG; + new_settings.c_cc[VMIN] = 0; + new_settings.c_cc[VTIME] = 0; + } + + int + peek_ch(void) + { int n; + + has_stdin = 1; + + tcsetattr(0, TCSANOW, &new_settings); + n = getchar(); + tcsetattr(0, TCSANOW, &initial_settings); + + return n; + } +#endif + int qrecv(Lextok *n, int full) { int whichq = eval(n->lft)-1; @@ -150,22 +180,37 @@ qrecv(Lextok *n, int full) if (whichq == -1) { if (n->sym && !strcmp(n->sym->name, "STDIN")) { Lextok *m; - +#ifndef PC + static int did_once = 0; + if (!did_once) /* 6.2.4 */ + { peek_ch_init(); + did_once = 1; + } +#endif if (TstOnly) return 1; for (m = n->rgt; m; m = m->rgt) if (m->lft->ntyp != CONST && m->lft->ntyp != EVAL) - { int c = getchar(); + { +#ifdef PC + int c = getchar(); +#else + int c = peek_ch(); /* 6.2.4, was getchar(); */ +#endif + if (c == 27 || c == 3) /* escape or control-c */ + { printf("quit\n"); + exit(0); + } /* else: non-blocking */ + if (c == EOF) return 0; /* no char available */ (void) setval(m->lft, c); } else - fatal("invalid use of STDIN", (char *)0); - - whichq = 0; + { fatal("invalid use of STDIN", (char *)0); + } return 1; } printf("Error: receiving from an uninitialized chan %s\n", n->sym?n->sym->name:""); - whichq = 0; + /* whichq = 0; */ return 0; } if (whichq < MAXQ && whichq >= 0 && ltab[whichq]) @@ -185,9 +230,11 @@ sa_snd(Queue *q, Lextok *n) /* sorted asynchronous */ for (j = 0, m = n->rgt; m && j < q->nflds; m = m->rgt, j++) { New = cast_val(q->fld_width[j], eval(m->lft), 0); Old = q->contents[i*q->nflds+j]; - if (New == Old) continue; - if (New > Old) break; /* inner loop */ - if (New < Old) goto found; + if (New == Old) + continue; + if (New > Old) + break; /* inner loop */ + goto found; /* New < Old */ } found: for (j = q->qlen-1; j >= i; j--) @@ -204,7 +251,8 @@ void typ_ck(int ft, int at, char *s) { if ((verbose&32) && ft != at - && (ft == CHAN || at == CHAN)) + && (ft == CHAN || at == CHAN) + && (at != PREDEF || strcmp(s, "recv") != 0)) { char buf[128], tag1[64], tag2[64]; (void) sputtype(tag1, ft); (void) sputtype(tag2, at); @@ -383,7 +431,7 @@ s_snd(Queue *q, Lextok *n) return 1; } -void +static void channm(Lextok *n) { char lbuf[512]; @@ -394,7 +442,11 @@ channm(Lextok *n) else if (n->sym->type == STRUCT) { Symbol *r = n->sym; if (r->context) - r = findloc(r); + { r = findloc(r); + if (!r) + { strcat(Buf, "*?*"); + return; + } } ini_struct(r); printf("%s", r->name); strcpy(lbuf, ""); @@ -422,7 +474,11 @@ difcolumns(Lextok *n, char *tr, int v, int j, Queue *q) sr_buf(v, q->fld_width[j] == MTYPE); if (j == q->nflds - 1) { int cnr; - if (s_trail) cnr = pno; else cnr = X?X->pid - Have_claim:0; + if (s_trail) + { cnr = pno; + } else + { cnr = X?X->pid - Have_claim:0; + } if (tr[0] == '[') strcat(Buf, "]"); pstext(cnr, Buf); } @@ -458,12 +514,6 @@ docolumns(Lextok *n, char *tr, int v, int j, Queue *q) } } -typedef struct QH { - int n; - struct QH *nxt; -} QH; -QH *qh; - void qhide(int q) { QH *p = (QH *) emalloc(sizeof(QH)); @@ -483,7 +533,7 @@ qishidden(int q) static void sr_talk(Lextok *n, int v, char *tr, char *a, int j, Queue *q) -{ char s[64]; +{ char s[128]; if (qishidden(eval(n->lft))) return; @@ -510,9 +560,20 @@ sr_talk(Lextok *n, int v, char *tr, char *a, int j, Queue *q) } if (j == 0) - { whoruns(1); - printf("line %3d %s %s", - n->ln, n->fn->name, s); + { char snm[128]; + whoruns(1); + { char *ptr = n->fn->name; + char *qtr = snm; + while (*ptr != '\0') + { if (*ptr != '\"') + { *qtr++ = *ptr; + } + ptr++; + } + *qtr = '\0'; + printf("%s:%d %s", + snm, n->ln, s); + } } else printf(","); sr_mesg(stdout, v, q->fld_width[j] == MTYPE); @@ -554,7 +615,11 @@ void sr_mesg(FILE *fd, int v, int j) { Buf[0] ='\0'; sr_buf(v, j); +#if 1 + fprintf(fd, Buf, (char *) 0); /* prevent compiler warning */ +#else fprintf(fd, Buf); +#endif } void @@ -572,10 +637,15 @@ doq(Symbol *s, int n, RunList *r) continue; if (q->nslots == 0) continue; /* rv q always empty */ +#if 0 + if (q->qlen == 0) /* new 7/10 -- dont show if queue is empty */ + { continue; + } +#endif printf("\t\tqueue %d (", q->qid); if (r) printf("%s(%d):", r->n->name, r->pid - Have_claim); - if (s->nel != 1) + if (s->nel > 1 || s->isarray) printf("%s[%d]): ", s->name, n); else printf("%s): ", s->name); @@ -609,7 +679,11 @@ nochan_manip(Lextok *p, Lextok *n, int d) } } - if (!n || n->ntyp == LEN || n->ntyp == RUN) + /* ok on the rhs of an assignment: */ + if (!n || n->ntyp == LEN || n->ntyp == RUN + || n->ntyp == FULL || n->ntyp == NFULL + || n->ntyp == EMPTY || n->ntyp == NEMPTY + || n->ntyp == 'R') return; if (n->sym && n->sym->type == CHAN) @@ -627,6 +701,121 @@ nochan_manip(Lextok *p, Lextok *n, int d) nochan_manip(p, n->rgt, 1); } +typedef struct BaseName { + char *str; + int cnt; + struct BaseName *nxt; +} BaseName; + +static BaseName *bsn; + +void +newbasename(char *s) +{ BaseName *b; + +/* printf("+++++++++%s\n", s); */ + for (b = bsn; b; b = b->nxt) + if (strcmp(b->str, s) == 0) + { b->cnt++; + return; + } + b = (BaseName *) emalloc(sizeof(BaseName)); + b->str = emalloc(strlen(s)+1); + b->cnt = 1; + strcpy(b->str, s); + b->nxt = bsn; + bsn = b; +} + +void +delbasename(char *s) +{ BaseName *b, *prv = (BaseName *) 0; + + for (b = bsn; b; prv = b, b = b->nxt) + { if (strcmp(b->str, s) == 0) + { b->cnt--; + if (b->cnt == 0) + { if (prv) + { prv->nxt = b->nxt; + } else + { bsn = b->nxt; + } } +/* printf("---------%s\n", s); */ + break; + } } +} + +void +checkindex(char *s, char *t) +{ BaseName *b; + +/* printf("xxx Check %s (%s)\n", s, t); */ + for (b = bsn; b; b = b->nxt) + { +/* printf(" %s\n", b->str); */ + if (strcmp(b->str, s) == 0) + { non_fatal("do not index an array with itself (%s)", t); + break; + } } +} + +void +scan_tree(Lextok *t, char *mn, char *mx) +{ char sv[512]; + char tmp[32]; + int oln = lineno; + + if (!t) return; + + lineno = t->ln; + + if (t->ntyp == NAME) + { strcat(mn, t->sym->name); + strcat(mx, t->sym->name); + if (t->lft) /* array index */ + { strcat(mn, "[]"); + newbasename(mn); + strcpy(sv, mn); /* save */ + strcpy(mn, ""); /* clear */ + strcat(mx, "["); + scan_tree(t->lft, mn, mx); /* index */ + strcat(mx, "]"); + checkindex(mn, mx); /* match against basenames */ + strcpy(mn, sv); /* restore */ + delbasename(mn); + } + if (t->rgt) /* structure element */ + { scan_tree(t->rgt, mn, mx); + } + } else if (t->ntyp == CONST) + { strcat(mn, "1"); /* really: t->val */ + sprintf(tmp, "%d", t->val); + strcat(mx, tmp); + } else if (t->ntyp == '.') + { strcat(mn, "."); + strcat(mx, "."); + scan_tree(t->lft, mn, mx); + } else + { strcat(mn, "??"); + strcat(mx, "??"); + } + lineno = oln; +} + +void +no_nested_array_refs(Lextok *n) /* a [ a[1] ] with a[1] = 1, causes trouble in pan.b */ +{ char mn[512]; + char mx[512]; + +/* printf("==================================ZAP\n"); */ + bsn = (BaseName *) 0; /* start new list */ + strcpy(mn, ""); + strcpy(mx, ""); + + scan_tree(n, mn, mx); +/* printf("==> %s\n", mn); */ +} + void no_internals(Lextok *n) { char *sp; @@ -638,7 +827,10 @@ no_internals(Lextok *n) sp = n->sym->name; if ((strlen(sp) == strlen("_nr_pr") && strcmp(sp, "_nr_pr") == 0) + || (strlen(sp) == strlen("_pid") && strcmp(sp, "_pid") == 0) || (strlen(sp) == strlen("_p") && strcmp(sp, "_p") == 0)) - { fatal("attempt to assign value to system variable %s", sp); + { fatal("invalid assignment to %s", sp); } + + no_nested_array_refs(n); } diff --git a/sys/src/cmd/spin/mkfile b/sys/src/cmd/spin/mkfile index abbef6239..80f9b95e4 100644 --- a/sys/src/cmd/spin/mkfile +++ b/sys/src/cmd/spin/mkfile @@ -8,14 +8,14 @@ SPIN_OS=\ guided.$O\ main.$O\ mesg.$O\ + msc_tcl.$O\ pangen1.$O\ pangen2.$O\ pangen3.$O\ pangen4.$O\ pangen5.$O\ pangen6.$O\ - pc_zpp.$O\ - ps_msc.$O\ + pangen7.$O\ reprosrc.$O\ run.$O\ sched.$O\ @@ -45,7 +45,7 @@ BIN=/$objtype/bin +#include "spin.h" +#include "version.h" + +#define MW 500 /* page width */ +#define RH 100 /* right margin */ +#define WW 80 /* distance between process lines */ +#define HH 12 /* vertical distance between steps */ +#define LW 2 /* line width of message arrows */ + +#define RVC "darkred" /* rendezvous arrows */ +#define MPC "darkblue" /* asynchronous message passing arrow */ +#define GRC "lightgrey" /* grid lines */ + +static int MH = 600; /* anticipated page-length */ +static FILE *pfd; +static char **I; /* initial procs */ +static int *D,*R; /* maps between depth (stepnr) and ldepth (msc-step) */ +static short *M; /* x location of each box at index y */ +static short *T; /* y index of match for each box at index y */ +static char **L; /* text labels */ +static int ProcLine[256]; /* active processes */ +static int UsedLine[256]; /* process line has at least one entry */ +static int ldepth = 1; +static int maxx, TotSteps = 2*4096; /* max nr of steps for simulation output */ +static float Scaler = (float) 1.0; + +static int xscale = 2; +static int yscale = 1; +static int no_box; + +extern int ntrail, s_trail, pno, depth; +extern Symbol *oFname; + +extern void exit(int); +extern void putpostlude(void); + +static void putpages(void); + +static void +psline(int x0, int y0, int x1, int y1, char *color) +{ char *side = "last"; + + if (x0 == x1) /* gridline */ + { fprintf(pfd, ".c create line %d %d %d %d -fill %s -tags grid -width 1 \n", + xscale*(x0+1)*WW-20, yscale*y0+20, + xscale*(x1+1)*WW-20, yscale*y1+20, color); + fprintf(pfd, ".c lower grid\n"); + } else + { int xm = xscale*(x0+1)*WW + (xscale*(x1 - x0)*WW)/2 - 20; /* mid x */ + + if (y1 - y0 <= HH+20) + { y1 = y0+20; /* close enough to horizontal - looks better */ + } + + fprintf(pfd, ".c create line %d %d %d %d -fill %s -tags mesg -width %d\n", + xscale*(x0+1)*WW-20, yscale*y0+20+10, + xm, yscale*y0+20+10, color, LW); + + if (y1 != y0+20) + { fprintf(pfd, ".c create line %d %d %d %d -fill %s -tags mesg -width %d\n", + xm, yscale*y0+20+10, + xm, yscale*y1+20-10, color, LW); + } + + fprintf(pfd, ".c create line %d %d %d %d -fill %s -width %d ", + xm, yscale*y1+20-10, + xscale*(x1+1)*WW-20, yscale*y1+20-10, color, LW); + + if (strcmp(color, RVC) == 0) + { side = "both"; + } + fprintf(pfd, "-arrow %s -arrowshape {5 5 5} -tags mesg\n", side); + fprintf(pfd, ".c raise mesg\n"); + } +} + +static void +colbox(int ix, int iy, int w, int h_unused, char *color) +{ int x = ix*WW; + int y = iy*HH; + + if (ix < 0 || ix > 255) + { fatal("msc_tcl: unexpected\n", (char *) 0); + } + + if (ProcLine[ix] < iy) + { /* if (ProcLine[ix] > 0) */ + { psline(ix-1, ProcLine[ix]*HH+HH+4, + ix-1, iy*HH-HH, GRC); + } + fprintf(pfd, "# ProcLine[%d] from %d to %d (Used %d nobox %d)\n", + ix, ProcLine[ix], iy, UsedLine[ix], no_box); + ProcLine[ix] = iy; + } else + { fprintf(pfd, "# ProcLine[%d] stays at %d (Used %d nobox %d)\n", + ix, ProcLine[ix], UsedLine[ix], no_box); + } + + if (UsedLine[ix]) + { no_box = 2; + } + + if (strcmp(color, "black") == 0) + { if (no_box == 0) /* shadow */ + { fprintf(pfd, ".c create rectangle %d %d %d %d -fill black\n", + xscale*x-(xscale*4*w/3)-20+4, (yscale*y-10)+20+2, + xscale*x+(xscale*4*w/3)-20, (yscale*y+10)+20+2); + } + } else + { if (no_box == 0) /* box with outline */ + { fprintf(pfd, ".c create rectangle %d %d %d %d -fill ivory\n", + xscale*x-(xscale*4*w/3)-20, (yscale*y-10)+20, + xscale*x+(xscale*4*w/3)-20, (yscale*y+10)+20); + UsedLine[ix]++; + } else /* no outline */ + { fprintf(pfd, ".c create rectangle %d %d %d %d -fill white -width 0\n", + xscale*x-(xscale*4*w/3)-20, (yscale*y-10)+20, + xscale*x+(xscale*4*w/3)-20, (yscale*y+10)+20); + } } + if (no_box > 0) + { no_box--; + } +} + +static void +stepnumber(int i) +{ int y = (yscale*i*HH) + 20; + + fprintf(pfd, ".c create text %d %d -fill #eef -text \"%d\"\n", + -10+(xscale*WW)/2, y, i); + + /* horizontal dashed grid line */ + fprintf(pfd, ".c create line %d %d %d %d -fill #eef -dash {6 4}\n", + -20+WW*xscale, y, (maxx+1)*WW*xscale-20, y); +} + +static void +spitbox(int ix, int y, char *s) +{ float bw; /* box width */ + char d[256], *t, *z; + int a, i, x = ix+1; + char *color = "black"; + + if (y > 0) + { stepnumber(y); + } + + bw = (float)1.8*(float)strlen(s); /* guess at default font width */ + colbox(x, y, (int) (bw+1.0), 5, "black"); + if (s[0] == '~') + { switch (s[1]) { + default : + case 'R': color = "red"; break; + case 'B': color = "blue"; break; + case 'G': color = "green"; break; + } + s += 2; + } else if (strchr(s, '!')) + { color = "ivory"; + } else if (strchr(s, '?')) + { color = "azure"; + } else + { color = "pink"; + if (sscanf(s, "%d:%250s", &a, d) == 2 + && a >= 0 && a < TotSteps) + { if (!I[a] || strlen(I[a]) <= strlen(s)) + { I[a] = (char *) emalloc((int) strlen(s)+1); + } + strcpy(I[a], s); + } } + + colbox(x, y, (int) bw, 4, color); + + z = t = (char *) emalloc(2*strlen(s)+1); + + for (i = 0; i < (int) strlen(s); i++) + { if (s[i] == '\n') + { continue; + } + if (s[i] == '[' || s[i] == ']') + { *t++ = '\\'; + } + *t++ = s[i]; + } + + fprintf(pfd, ".c create text %d %d -text \"%s\"\n", + xscale*x*WW-20, yscale*y*HH+20, z); +} + +static void +putpages(void) +{ int i, lasti=0; float nmh; + + if (maxx*xscale*WW > MW-RH/2) + { Scaler = (float) (MW-RH/2) / (float) (maxx*xscale*WW); + nmh = (float) MH; nmh /= Scaler; MH = (int) nmh; + fprintf(pfd, "# Scaler %f, MH %d\n", Scaler, MH); + } + if (ldepth >= TotSteps) + { ldepth = TotSteps-1; + } + +/* W: (maxx+2)*xscale*WW */ +/* H: ldepth*HH*yscale+50 */ + fprintf(pfd, "wm title . \"scenario\"\n"); + fprintf(pfd, "wm geometry . %dx600+650+100\n", (maxx+2)*xscale*WW); + + fprintf(pfd, "canvas .c -width 800 -height 800 \\\n"); + fprintf(pfd, " -scrollregion {0c -1c 30c 100c} \\\n"); + fprintf(pfd, " -xscrollcommand \".hscroll set\" \\\n"); + fprintf(pfd, " -yscrollcommand \".vscroll set\" \\\n"); + fprintf(pfd, " -bg white -relief raised -bd 2\n"); + + fprintf(pfd, "scrollbar .vscroll -relief sunken "); + fprintf(pfd, " -command \".c yview\"\n"); + fprintf(pfd, "scrollbar .hscroll -relief sunken -orient horiz "); + fprintf(pfd, " -command \".c xview\"\n"); + + fprintf(pfd, "pack append . \\\n"); + fprintf(pfd, " .vscroll {right filly} \\\n"); + fprintf(pfd, " .hscroll {bottom fillx} \\\n"); + fprintf(pfd, " .c {top expand fill}\n"); + + fprintf(pfd, ".c yview moveto 0\n"); + + for (i = TotSteps-1; i >= 0; i--) + { if (I[i]) + { spitbox(i, -1, I[i]); + } } + + for (i = 0; i <= ldepth; i++) + { if (!M[i] && !L[i]) + { continue; /* no box */ + } + if (T[i] > 0) /* arrow */ + { if (T[i] == i) /* rv handshake */ + { psline( M[lasti], lasti*HH, + M[i], i*HH, RVC); + } else + { psline( M[i], i*HH, + M[T[i]], T[i]*HH, MPC); + } } + if (L[i]) + { spitbox(M[i], i, L[i]); + lasti = i; + } } +} + +static void +putbox(int x) +{ + if (ldepth >= TotSteps) + { fprintf(stderr, "max length of %d steps exceeded - ps file truncated\n", + TotSteps); + putpostlude(); + } + M[ldepth] = x; + if (x > maxx) + { maxx = x; + fprintf(pfd, "# maxx %d\n", x); + } +} + +/* functions called externally: */ + +extern int WhatSeed(void); + +void +putpostlude(void) +{ char cmd[512]; + + putpages(); + fprintf(pfd, ".c lower grid\n"); + fprintf(pfd, ".c raise mesg\n"); + fclose(pfd); + + fprintf(stderr, "seed used: -n%d\n", WhatSeed()); + sprintf(cmd, "wish -f %s.tcl &", oFname?oFname->name:"msc"); + fprintf(stderr, "%s\n", cmd); + (void) unlink("pan.pre"); + exit (system(cmd)); +} + +void +putprelude(void) +{ char snap[256]; FILE *fd; + + sprintf(snap, "%s.tcl", oFname?oFname->name:"msc"); + if (!(pfd = fopen(snap, MFLAGS))) + { fatal("cannot create file '%s'", snap); + } + if (s_trail) + { if (ntrail) + sprintf(snap, "%s%d.trail", oFname?oFname->name:"msc", ntrail); + else + sprintf(snap, "%s.trail", oFname?oFname->name:"msc"); + if (!(fd = fopen(snap, "r"))) + { snap[strlen(snap)-2] = '\0'; + if (!(fd = fopen(snap, "r"))) + fatal("cannot open trail file", (char *) 0); + } + TotSteps = 1; + while (fgets(snap, 256, fd)) TotSteps++; + fclose(fd); + } + TotSteps *= 2; + R = (int *) emalloc(TotSteps * sizeof(int)); + D = (int *) emalloc(TotSteps * sizeof(int)); + M = (short *) emalloc(TotSteps * sizeof(short)); + T = (short *) emalloc(TotSteps * sizeof(short)); + L = (char **) emalloc(TotSteps * sizeof(char *)); + I = (char **) emalloc(TotSteps * sizeof(char *)); +} + +void +putarrow(int from, int to) +{ + /* from rv if from == to */ + /* which means that D[from] == D[to] */ + /* which means that T[x] == x */ + + if (from < TotSteps + && to < TotSteps + && D[from] < TotSteps) + { T[D[from]] = D[to]; + } +} + +void +pstext(int x, char *s) +{ char *tmp = emalloc((int) strlen(s)+1); + + strcpy(tmp, s); + if (depth == 0) + { I[x] = tmp; + } else + { if (depth >= TotSteps || ldepth >= TotSteps) + { fprintf(stderr, "spin: error: max nr of %d steps exceeded\n", + TotSteps); + fatal("use -uN to limit steps", (char *) 0); + } + putbox(x); + D[depth] = ldepth; + R[ldepth] = depth; + L[ldepth] = tmp; + ldepth += 2; + } +} + +void +dotag(FILE *fd, char *s) +{ 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 + { if (!notabs) + { printf(" "); + for (i = 0; i <= pid; i++) + { printf(" "); + } } + fprintf(fd, "%s", s); + fflush(fd); + } +} diff --git a/sys/src/cmd/spin/pangen1.c b/sys/src/cmd/spin/pangen1.c index cbef9dba5..3a537626d 100644 --- a/sys/src/cmd/spin/pangen1.c +++ b/sys/src/cmd/spin/pangen1.c @@ -1,18 +1,22 @@ /***** spin: pangen1.c *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #include "spin.h" #include "y.tab.h" #include "pangen1.h" #include "pangen3.h" +#include "pangen6.h" +#include +#ifdef SOLARIS +#include +#else +#include +#endif extern FILE *tc, *th, *tt; extern Label *labtab; @@ -20,9 +24,10 @@ extern Ordered *all_names; extern ProcList *rdy; extern Queue *qtab; extern Symbol *Fname; -extern int lineno, verbose, Pid, separate; +extern int lineno, verbose, Pid, separate, old_scope_rules, nclaims; extern int nrRdy, nqs, mst, Mpars, claimnr, eventmapnr; -extern short has_sorted, has_random, has_provided; +extern short has_sorted, has_random, has_provided, has_priority; +extern Queue *ltab[]; int Npars=0, u_sync=0, u_async=0, hastrack = 1; short has_io = 0; @@ -36,9 +41,10 @@ static int doglobal(char *, int); static void dohidden(void); static void do_init(FILE *, Symbol *); static void end_labs(Symbol *, int); -static void put_ptype(char *, int, int, int); +static void put_ptype(char *, int, int, int, enum btypes); static void tc_predef_np(void); static void put_pinit(ProcList *); +static void multi_init(void); void walk_struct(FILE *, int, char *, Symbol *, char *, char *, char *); static void @@ -46,7 +52,22 @@ reverse_names(ProcList *p) { if (!p) return; reverse_names(p->nxt); - fprintf(th, " \"%s\",\n", p->n->name); + fprintf(tc, " \"%s\",\n", p->n->name); +} +static void +reverse_types(ProcList *p) +{ + if (!p) return; + reverse_types(p->nxt); + fprintf(tc, " %d, /* %s */\n", p->b, p->n->name); +} + +static int +blog(int n) /* for small log2 without rounding problems */ +{ int m=1, r=2; + + while (r < n) { m++; r *= 2; } + return 1+m; } void @@ -57,37 +78,129 @@ genheader(void) { putunames(th); goto here; } - + /* 5.2.3: gcc 3 no longer seems to compute sizeof at compile time */ + fprintf(th, "#define WS %d /* word size in bytes */\n", (int) sizeof(void *)); fprintf(th, "#define SYNC %d\n", u_sync); fprintf(th, "#define ASYNC %d\n\n", u_async); + fprintf(th, "#ifndef NCORE\n"); + fprintf(th, " #ifdef DUAL_CORE\n"); + fprintf(th, " #define NCORE 2\n"); + fprintf(th, " #elif QUAD_CORE\n"); + fprintf(th, " #define NCORE 4\n"); + fprintf(th, " #else\n"); + fprintf(th, " #define NCORE 1\n"); + fprintf(th, " #endif\n"); + fprintf(th, "#endif\n\n"); putunames(th); - fprintf(tc, "short Air[] = { "); + fprintf(tc, "\nshort Air[] = { "); for (p = rdy, i=0; p; p = p->nxt, i++) fprintf(tc, "%s (short) Air%d", (p!=rdy)?",":"", i); fprintf(tc, ", (short) Air%d", i); /* np_ */ + if (nclaims > 1) + { fprintf(tc, "\n#ifndef NOCLAIM\n"); + fprintf(tc, " , (short) Air%d", i+1); /* Multi */ + fprintf(tc, "\n#endif\n\t"); + } fprintf(tc, " };\n"); - fprintf(th, "char *procname[] = {\n"); + fprintf(tc, "char *procname[] = {\n"); reverse_names(rdy); - fprintf(th, " \":np_:\",\n"); - fprintf(th, "};\n\n"); + fprintf(tc, " \":np_:\",\n"); + fprintf(tc, " 0\n"); + fprintf(tc, "};\n\n"); + + fprintf(tc, "enum btypes { NONE=%d, N_CLAIM=%d,", NONE, N_CLAIM); + fprintf(tc, " I_PROC=%d, A_PROC=%d,", I_PROC, A_PROC); + fprintf(tc, " P_PROC=%d, E_TRACE=%d, N_TRACE=%d };\n\n", + P_PROC, E_TRACE, N_TRACE); + + fprintf(tc, "int Btypes[] = {\n"); + reverse_types(rdy); + fprintf(tc, " 0 /* :np_: */\n"); + fprintf(tc, "};\n\n"); here: for (p = rdy; p; p = p->nxt) - put_ptype(p->n->name, p->tn, mst, nrRdy+1); + put_ptype(p->n->name, p->tn, mst, nrRdy+1, p->b); /* +1 for np_ */ - put_ptype("np_", nrRdy, mst, nrRdy+1); + put_ptype("np_", nrRdy, mst, nrRdy+1, 0); + + if (nclaims > 1) + { /* this is the structure that goes into the state-vector + * instead of the actual never claims + * this assumes that the claims do not have any local variables + * this claim records the types and states of all subclaims in an array + * NB: not sure if we need the first 3 fields in this structure + * it's here for now to avoid breaking some possible dependence + * in the calculations above, we were already taking into account + * that there is one never-claim, which will now be this one + */ + + i = blog(mst); + fprintf(th, "\n"); + + fprintf(th, "#ifndef NOCLAIM\n"); + fprintf(th, " #undef VERI\n"); + fprintf(th, " #define VERI %d\n", nrRdy+1); + fprintf(th, " #define Pclaim P%d\n\n", nrRdy+1); + fprintf(th, "typedef struct P%d {\n", nrRdy+1); + fprintf(th, " unsigned _pid : 8; /* always zero */\n"); + fprintf(th, " unsigned _t : %d; /* active-claim type */\n", + blog(nrRdy+1)); + fprintf(th, " unsigned _p : %d; /* active-claim state */\n", + i); + fprintf(th, " unsigned _n : %d; /* active-claim index */\n", + blog(nclaims)); + if (i <= UINT8_MAX) /* in stdint.h = UCHAR_MAX from limits.h */ + { fprintf(th, " uchar c_cur[NCLAIMS]; /* claim-states */\n"); + } else if (i <= UINT16_MAX) /* really USHRT_MAX from limits.h */ + { fprintf(th, " ushort c_cur[NCLAIMS]; /* claim-states */\n"); + } else /* the most unlikely case */ + { fprintf(th, " uint c_cur[NCLAIMS]; /* claim-states */\n"); + } + fprintf(th, "} P%d;\n", nrRdy+1); + + fprintf(tc, "#ifndef NOCLAIM\n"); + fprintf(tc, "uchar spin_c_typ[NCLAIMS]; /* claim-types */\n"); + fprintf(tc, "#endif\n"); + + fprintf(th, " #define Air%d (0)\n\n", nrRdy+1); + fprintf(th, "#endif\n"); + /* + * find special states as: + * stopstate [ claimnr ][ curstate ] == 1 + * accpstate [ claimnr ][ curstate ] + * progstate [ claimnr ][ curstate ] + * reached [ claimnr ][ curstate ] + * visstate [ claimnr ][ curstate ] + * loopstate [ claimnr ][ curstate ] + * mapstate [ claimnr ][ curstate ] + */ + } else + { fprintf(th, "#define Pclaim P0\n"); + fprintf(th, "#ifndef NCLAIMS\n"); + fprintf(th, " #define NCLAIMS 1\n"); + fprintf(th, "#endif\n"); + fprintf(tc, "uchar spin_c_typ[NCLAIMS]; /* claim-types */\n"); + } ntimes(th, 0, 1, Head0); if (separate != 2) { extern void c_add_stack(FILE *); + extern void c_stack_size(FILE *); ntimes(th, 0, 1, Header); + fprintf(th, "#define StackSize ("); + c_stack_size(th); + fprintf(th, ")\n"); + c_add_stack(th); ntimes(th, 0, 1, Header0); + } else + { fprintf(th, "extern char *emalloc(unsigned long);\n"); } ntimes(th, 0, 1, Head1); @@ -96,7 +209,13 @@ here: hastrack = c_add_sv(th); + fprintf(th, "#ifdef TRIX\n"); + fprintf(th, " /* room for 512 proc+chan ptrs, + safety margin */\n"); + fprintf(th, " char *_ids_[MAXPROC+MAXQ+4];\n"); + fprintf(th, "#else\n"); fprintf(th, " uchar sv[VECTORSZ];\n"); + fprintf(th, "#endif\n"); + fprintf(th, "} State"); #ifdef SOLARIS fprintf(th,"\n#ifdef GCC\n"); @@ -105,8 +224,24 @@ here: #endif fprintf(th, ";\n\n"); - fprintf(th, "#define HAS_TRACK %d\n", hastrack); + fprintf(th, "#ifdef TRIX\n"); + fprintf(th, "typedef struct TRIX_v6 {\n"); + fprintf(th, " uchar *body; /* aligned */\n"); + fprintf(th, "#ifndef BFS\n"); + fprintf(th, " short modified;\n"); + fprintf(th, "#endif\n"); + fprintf(th, " short psize;\n"); + fprintf(th, " short parent_pid;\n"); + fprintf(th, " struct TRIX_v6 *nxt;\n"); + fprintf(th, "} TRIX_v6;\n"); + fprintf(th, "#endif\n\n"); + fprintf(th, "#define HAS_TRACK %d\n", hastrack); + if (0 && hastrack) /* not really a problem */ + { fprintf(th, "#ifdef BFS_PAR\n"); + fprintf(th, " #error cannot use BFS_PAR on models with c_track stmnts\n"); + fprintf(th, "#endif\n"); + } if (separate != 2) dohidden(); } @@ -116,14 +251,36 @@ genaddproc(void) { ProcList *p; int i = 0; - if (separate ==2) goto shortcut; + if (separate == 2) goto shortcut; - fprintf(tc, "int\naddproc(int n"); - for (i = 0; i < Npars; i++) + ntimes(tc, nrRdy+1, nrRdy+2, R2); /* +1 for np_ -- was th */ + + fprintf(tc, "#ifdef TRIX\n"); + fprintf(tc, "int what_p_size(int);\n"); + fprintf(tc, "int what_q_size(int);\n\n"); + + /* the number of processes just changed by 1 (up or down) */ + /* this means that the channel indices move up or down by one slot */ + /* not all new channels may have a valid index yet, but we move */ + /* all of them anyway, as if they existed */ + ntimes(tc, 0, 1, R7a); + fprintf(tc, "#endif\n\n"); + + ntimes(tc, 0, 1, R7b); + + fprintf(tc, "int\naddproc(int calling_pid, int priority, int n"); + for (/* i = 0 */; i < Npars; i++) fprintf(tc, ", int par%d", i); ntimes(tc, 0, 1, Addp0); ntimes(tc, 1, nrRdy+1, R5); /* +1 for np_ */ + + if (nclaims > 1) + { fprintf(tc, "#ifndef NOCLAIM\n"); + ntimes(tc, nrRdy+1, nrRdy+2, R5); + fprintf(tc, "#endif\n"); + } + ntimes(tc, 0, 1, Addp1); if (has_provided) @@ -132,6 +289,9 @@ genaddproc(void) fprintf(tt, "{\n\tswitch(ot) {\n"); } shortcut: + if (nclaims > 1) + { multi_init(); + } tc_predef_np(); for (p = rdy; p; p = p->nxt) { Pid = p->tn; @@ -157,8 +317,17 @@ void do_locinits(FILE *fd) { ProcList *p; + /* the locinit functions may refer to pptr or qptr */ + fprintf(fd, "#if VECTORSZ>32000\n"); + fprintf(fd, " extern int \n"); + fprintf(fd, "#else\n"); + fprintf(fd, " extern short \n"); + fprintf(fd, "#endif\n"); + fprintf(fd, " *proc_offset, *q_offset;\n"); + for (p = rdy; p; p = p->nxt) - c_add_locinit(fd, p->tn, p->n->name); + { c_add_locinit(fd, p->tn, p->n->name); + } } void @@ -167,63 +336,89 @@ genother(void) switch (separate) { case 2: - if (claimnr >= 0) - ntimes(tc, claimnr, claimnr+1, R0); /* claim only */ + if (nclaims > 0) + { for (p = rdy; p; p = p->nxt) + { if (p->b == N_CLAIM) + { ntimes(tc, p->tn, p->tn+1, R0); /* claims only */ + fprintf(tc, "#ifdef HAS_CODE\n"); + ntimes(tc, p->tn, p->tn+1, R00); + fprintf(tc, "#endif\n"); + } } } break; case 1: ntimes(tc, 0, 1, Code0); - ntimes(tc, 0, claimnr, R0); /* all except claim */ - ntimes(tc, claimnr+1, nrRdy, R0); + for (p = rdy; p; p = p->nxt) + { if (p->b != N_CLAIM) + { ntimes(tc, p->tn, p->tn+1, R0); /* all except claims */ + fprintf(tc, "#ifdef HAS_CODE\n"); + ntimes(tc, p->tn, p->tn+1, R00); + fprintf(tc, "#endif\n"); + } } break; case 0: ntimes(tc, 0, 1, Code0); ntimes(tc, 0, nrRdy+1, R0); /* +1 for np_ */ + fprintf(tc, "#ifdef HAS_CODE\n"); + ntimes(tc, 0, nrRdy+1, R00); /* +1 for np_ */ + fprintf(tc, "#endif\n"); break; } + /* new place, make sure Maxbody is set to its final value here */ + fprintf(tc, "\n"); + + if (separate != 2) + { ntimes(tc, 1, u_sync+u_async+1, R3); /* nqs is still 0 */ + fprintf(tc, "\tMaxbody = max(Maxbody, sizeof(State)-VECTORSZ);\n"); + fprintf(tc, "\tif ((Maxbody %% WS) != 0)\n"); + fprintf(tc, "\t Maxbody += WS - (Maxbody %% WS);\n\n"); + } for (p = rdy; p; p = p->nxt) end_labs(p->n, p->tn); switch (separate) { case 2: - if (claimnr >= 0) - ntimes(tc, claimnr, claimnr+1, R0a); /* claim only */ + if (nclaims > 0) + { for (p = rdy; p; p = p->nxt) + { if (p->b == N_CLAIM) + { ntimes(tc, p->tn, p->tn+1, R0a); /* claims only */ + } } } return; case 1: - ntimes(tc, 0, claimnr, R0a); /* all except claim */ - ntimes(tc, claimnr+1, nrRdy, R0a); + for (p = rdy; p; p = p->nxt) + { if (p->b != N_CLAIM) + { ntimes(tc, p->tn, p->tn+1, R0a); /* all except claims */ + } } fprintf(tc, " if (state_tables)\n"); - fprintf(tc, " ini_claim(%d, 0);\n", claimnr); + fprintf(tc, " ini_claim(%d, 0);\n", claimnr); /* the default claim */ + if (acceptors == 0) + { acceptors = 1; /* assume at least 1 acceptstate */ + } break; case 0: ntimes(tc, 0, nrRdy, R0a); /* all */ break; } - ntimes(tc, 0, 1, R0b); - if (separate == 1 && acceptors == 0) - acceptors = 1; /* assume at least 1 acceptstate */ ntimes(th, acceptors, acceptors+1, Code1); ntimes(th, progressors, progressors+1, Code3); - ntimes(th, nrRdy+1, nrRdy+2, R2); /* +1 for np_ */ - fprintf(tc, " iniglobals();\n"); - ntimes(tc, 0, 1, Code2a); - ntimes(tc, 0, 1, Code2b); /* bfs option */ - ntimes(tc, 0, 1, Code2c); + ntimes(tc, 0, 1, Code2a); /* dfs, bfs */ + ntimes(tc, 0, 1, Code2e); /* multicore */ + ntimes(tc, 0, 1, Code2c); /* multicore */ + ntimes(tc, 0, 1, Code2d); + + fprintf(tc, "void\ndo_reach(void)\n{\n"); ntimes(tc, 0, nrRdy, R4); fprintf(tc, "}\n\n"); - fprintf(tc, "void\n"); - fprintf(tc, "iniglobals(void)\n{\n"); + fprintf(tc, "void\niniglobals(int calling_pid)\n{\n"); if (doglobal("", INIV) > 0) { fprintf(tc, "#ifdef VAR_RANGES\n"); (void) doglobal("logval(\"", LOGV); fprintf(tc, "#endif\n"); } - ntimes(tc, 1, nqs+1, R3); - fprintf(tc, "\tMaxbody = max(Maxbody, sizeof(State)-VECTORSZ);"); - fprintf(tc, "\n}\n\n"); + fprintf(tc, "}\n\n"); } void @@ -248,17 +443,17 @@ end_labs(Symbol *s, int i) Label *l; int j; char foo[128]; - if ((i == claimnr && separate == 1) - || (i != claimnr && separate == 2)) + if ((pid_is_claim(i) && separate == 1) + || (!pid_is_claim(i) && separate == 2)) return; for (l = labtab; l; l = l->nxt) for (j = 0; ln[j].n; j++) - if (strncmp(l->s->name, ln[j].s, ln[j].n) == 0 + { if (strncmp(l->s->name, ln[j].s, ln[j].n) == 0 && strcmp(l->c->name, s->name) == 0) { fprintf(tc, "\t%s[%d][%d] = 1;\n", ln[j].t, i, l->e->seqno); - acceptors += ln[j].m; + acceptors += ln[j].m; progressors += ln[j].p; if (l->e->status & D_ATOM) { sprintf(foo, "%s label inside d_step", @@ -272,8 +467,7 @@ end_labs(Symbol *s, int i) Fname = l->e->n->fn; printf("spin: %3d:%s, warning, %s - is invisible\n", lineno, Fname?Fname->name:"-", foo); - } - } + } } } /* visible states -- through remote refs: */ for (l = labtab; l; l = l->nxt) if (l->visible @@ -286,7 +480,7 @@ end_labs(Symbol *s, int i) } void -ntimes(FILE *fd, int n, int m, char *c[]) +ntimes(FILE *fd, int n, int m, const char *c[]) { int i, j; for (j = 0; c[j]; j++) @@ -305,7 +499,7 @@ prehint(Symbol *s) n = (s->context != ZS)?s->context->ini:s->ini; if (n) - printf("line %3d %s, ", n->ln, n->fn->name); + printf("line %s:%d, ", n->fn->name, n->ln); } void @@ -338,7 +532,7 @@ checktype(Symbol *sp, char *s) { if (!(verbose&32)) return; sputtype(buf, sp->type); i = (int) strlen(buf); - while (buf[--i] == ' ') buf[i] = '\0'; + while (i > 0 && buf[--i] == ' ') buf[i] = '\0'; prehint(sp); if (sp->context) printf("proctype %s:", s); @@ -361,12 +555,12 @@ checktype(Symbol *sp, char *s) } } -int -dolocal(FILE *ofd, char *pre, int dowhat, int p, char *s) +static int +dolocal(FILE *ofd, char *pre, int dowhat, int p, char *s, enum btypes b) { int h, j, k=0; extern int nr_errs; Ordered *walk; Symbol *sp; - char buf[64], buf2[128], buf3[128]; + char buf[128], buf2[128], buf3[128]; if (dowhat == INIV) { /* initialize in order of declaration */ @@ -390,7 +584,8 @@ dolocal(FILE *ofd, char *pre, int dowhat, int p, char *s) if (sp->context && !sp->owner && sp->type == Types[j] - && ((h == 0 && sp->nel == 1) || (h == 1 && sp->nel > 1)) + && ((h == 0 && (sp->nel == 1 && sp->isarray == 0)) + || (h == 1 && (sp->nel > 1 || sp->isarray == 1))) && strcmp(s, sp->context->name) == 0) { switch (dowhat) { case LOGV: @@ -409,7 +604,7 @@ dolocal(FILE *ofd, char *pre, int dowhat, int p, char *s) k++; break; } - if (strcmp(s, ":never:") == 0) + if (b == N_CLAIM) { printf("error: %s defines local %s\n", s, sp->name); nr_errs++; @@ -425,8 +620,8 @@ c_chandump(FILE *fd) int i; if (!qtab) - { fprintf(fd, "void\nc_chandump(int unused) "); - fprintf(fd, "{ unused = unused++; /* avoid complaints */ }\n"); + { fprintf(fd, "void\nc_chandump(int unused)\n"); + fprintf(fd, "{\tunused++; /* avoid complaints */\n}\n"); return; } @@ -465,9 +660,19 @@ c_chandump(FILE *fd) void c_var(FILE *fd, char *pref, Symbol *sp) -{ char buf[256]; +{ char *ptr, buf[256]; int i; + if (!sp) + { fatal("cannot happen - c_var", 0); + } + + ptr = sp->name; + if (!old_scope_rules) + { while (*ptr == '_' || isdigit((int)*ptr)) + { ptr++; + } } + switch (sp->type) { case STRUCT: /* c_struct(fd, pref, sp); */ @@ -476,34 +681,40 @@ c_var(FILE *fd, char *pref, Symbol *sp) sprintf(buf, "%s%s.", pref, sp->name); c_struct(fd, buf, sp); break; + case MTYPE: 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); + if (sp->nel == 1 && sp->isarray == 0) + { + if (sp->type == MTYPE && ismtype(sp->name)) + { fprintf(fd, "\tprintf(\"\t%s %s:\t%d\\n\");\n", + buf, ptr, ismtype(sp->name)); + } else + { fprintf(fd, "\tprintf(\"\t%s %s:\t%%d\\n\", %s%s);\n", + buf, ptr, pref, sp->name); + } } else { fprintf(fd, "\t{\tint l_in;\n"); fprintf(fd, "\t\tfor (l_in = 0; l_in < %d; l_in++)\n", sp->nel); fprintf(fd, "\t\t{\n"); fprintf(fd, "\t\t\tprintf(\"\t%s %s[%%d]:\t%%d\\n\", l_in, %s%s[l_in]);\n", - buf, sp->name, pref, sp->name); + buf, ptr, pref, sp->name); fprintf(fd, "\t\t}\n"); fprintf(fd, "\t}\n"); } break; case CHAN: - if (sp->nel == 1) - { fprintf(fd, "\tprintf(\"\tchan %s (=%%d):\tlen %%d:\\t\", ", - sp->name); + if (sp->nel == 1 && sp->isarray == 0) + { fprintf(fd, "\tprintf(\"\tchan %s (=%%d):\tlen %%d:\\t\", ", ptr); 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); + ptr, 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", @@ -518,9 +729,7 @@ c_splurge_any(ProcList *p) { Ordered *walk; Symbol *sp; - if (strcmp(p->n->name, ":never:") != 0 - && strcmp(p->n->name, ":trace:") != 0 - && strcmp(p->n->name, ":notrace:") != 0) + if (p->b != N_CLAIM && p->b != E_TRACE && p->b != N_TRACE) for (walk = all_names; walk; walk = walk->next) { sp = walk->entry; if (!sp->context @@ -541,9 +750,7 @@ c_splurge(FILE *fd, ProcList *p) Symbol *sp; char pref[64]; - if (strcmp(p->n->name, ":never:") != 0 - && strcmp(p->n->name, ":trace:") != 0 - && strcmp(p->n->name, ":notrace:") != 0) + if (p->b != N_CLAIM && p->b != E_TRACE && p->b != N_TRACE) for (walk = all_names; walk; walk = walk->next) { sp = walk->entry; if (!sp->context @@ -571,10 +778,8 @@ c_wrapper(FILE *fd) /* allow pan.c to print out global sv entries */ 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))) + if (sp->context || sp->owner || (sp->hidden&1)) continue; - c_var(fd, "now.", sp); } fprintf(fd, "}\n"); @@ -583,8 +788,6 @@ c_wrapper(FILE *fd) /* allow pan.c to print out global sv entries */ 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); if (c_splurge_any(p)) { fprintf(fd, " \tprintf(\"local vars proc %%d (%s):\\n\", pid);\n", p->n->name); @@ -633,8 +836,9 @@ doglobal(char *pre, int dowhat) checktype(sp, (char *) 0); cnt++; /* fall through */ case PUTV: - do_var(tc, dowhat, (sp->hidden&1)?"":"now.", sp, - "", " = ", ";\n"); + do_var(tc, dowhat, + (sp->hidden&1)?"":"now.", sp, + "", " = ", ";\n"); break; } } } return cnt; @@ -652,28 +856,37 @@ dohidden(void) if ((sp->hidden&1) && sp->type == Types[j]) { if (sp->context || sp->owner) - fatal("cannot hide non-globals (%s)", sp->name); + fatal("cannot hide non-globals (%s)", sp->name); if (sp->type == CHAN) - fatal("cannot hide channels (%s)", sp->name); + fatal("cannot hide channels (%s)", sp->name); fprintf(th, "/* hidden variable: */"); typ2c(sp); } } - fprintf(th, "int _; /* a predefined write-only variable */\n\n"); } void do_var(FILE *ofd, int dowhat, char *s, Symbol *sp, char *pre, char *sep, char *ter) { int i; + char *ptr = sp?sp->name:""; + + if (!sp) + { fatal("cannot happen - do_var", 0); + } switch(dowhat) { case PUTV: - if (sp->hidden&1) break; typ2c(sp); break; + case LOGV: + if (!old_scope_rules) + { while (*ptr == '_' || isdigit((int)*ptr)) + { ptr++; + } } + /* fall thru */ case INIV: if (sp->type == STRUCT) { /* struct may contain a chan */ @@ -682,13 +895,16 @@ do_var(FILE *ofd, int dowhat, char *s, Symbol *sp, } if (!sp->ini && dowhat != LOGV) /* it defaults to 0 */ break; - if (sp->nel == 1) - { fprintf(ofd, "\t\t%s%s%s%s", - pre, s, sp->name, sep); - if (dowhat == LOGV) + if (sp->nel == 1 && sp->isarray == 0) + { if (dowhat == LOGV) + { fprintf(ofd, "\t\t%s%s%s%s", + pre, s, ptr, sep); fprintf(ofd, "%s%s", s, sp->name); - else + } else + { fprintf(ofd, "\t\t%s%s%s%s", + pre, s, sp->name, sep); do_init(ofd, sp); + } fprintf(ofd, "%s", ter); } else { if (sp->ini && sp->ini->ntyp == CHAN) @@ -702,77 +918,86 @@ do_var(FILE *ofd, int dowhat, char *s, Symbol *sp, do_init(ofd, sp); fprintf(ofd, "%s", ter); } - } else - { fprintf(ofd, "\t{\tint l_in;\n"); - fprintf(ofd, "\t\tfor (l_in = 0; l_in < %d; l_in++)\n", sp->nel); - fprintf(ofd, "\t\t{\n"); - fprintf(ofd, "\t\t\t%s%s%s[l_in]%s", + } else if (sp->ini) + { if (dowhat != LOGV && sp->isarray && sp->ini->ntyp == ',') + { Lextok *z, *y; + z = sp->ini; + for (i = 0; i < sp->nel; i++) + { if (z && z->ntyp == ',') + { y = z->lft; + z = z->rgt; + } else + { y = z; + } + fprintf(ofd, "\t\t%s%s%s[%d]%s", + pre, s, sp->name, i, sep); + putstmnt(ofd, y, 0); + fprintf(ofd, "%s", ter); + } + } else + { fprintf(ofd, "\t{\tint l_in;\n"); + fprintf(ofd, "\t\tfor (l_in = 0; l_in < %d; l_in++)\n", + sp->nel); + fprintf(ofd, "\t\t{\n"); + fprintf(ofd, "\t\t\t%s%s%s[l_in]%s", pre, s, sp->name, sep); - if (dowhat == LOGV) - fprintf(ofd, "%s%s[l_in]", s, sp->name); - else - putstmnt(ofd, sp->ini, 0); - fprintf(ofd, "%s", ter); - fprintf(ofd, "\t\t}\n"); - fprintf(ofd, "\t}\n"); - } } + if (dowhat == LOGV) + { fprintf(ofd, "%s%s[l_in]", s, sp->name); + } else + { putstmnt(ofd, sp->ini, 0); + } + fprintf(ofd, "%s", ter); + fprintf(ofd, "\t\t}\n"); + fprintf(ofd, "\t}\n"); + } } } break; } } static void do_init(FILE *ofd, Symbol *sp) -{ int i; extern Queue *ltab[]; +{ int i; if (sp->ini && sp->type == CHAN && ((i = qmake(sp)) > 0)) { if (sp->ini->ntyp == CHAN) - fprintf(ofd, "addqueue(%d, %d)", - i, ltab[i-1]->nslots == 0); - else - fprintf(ofd, "%d", i); + { fprintf(ofd, "addqueue(calling_pid, %d, %d)", + i, ltab[i-1]->nslots == 0); + } else + { fprintf(ofd, "%d", i); + } } else - putstmnt(ofd, sp->ini, 0); -} - -static int -blog(int n) /* for small log2 without rounding problems */ -{ int m=1, r=2; - - while (r < n) { m++; r *= 2; } - return 1+m; + { putstmnt(ofd, sp->ini, 0); + } } static void -put_ptype(char *s, int i, int m0, int m1) +put_ptype(char *s, int i, int m0, int m1, enum btypes b) { 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); + if (b == I_PROC) + { fprintf(th, "#define Pinit ((P%d *)this)\n", i); + } else if (b == P_PROC || b == A_PROC) + { 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)); + fprintf(th, "#ifdef HAS_PRIORITY\n"); + fprintf(th, " unsigned _priority : 8; /* 0..255 */\n"); + fprintf(th, "#endif\n"); LstSet = ZS; nBits = 8 + blog(m1) + blog(m0); - k = dolocal(tc, "", PUTV, i, s); /* includes pars */ - + k = dolocal(tc, "", PUTV, i, s, b); /* includes pars */ c_add_loc(th, s); fprintf(th, "} P%d;\n", i); if ((!LstSet && k > 0) || has_state) - fprintf(th, "#define Air%d 0\n", i); - else + fprintf(th, "#define Air%d 0\n\n", i); + else if (LstSet || k == 0) /* 5.0, added condition */ { fprintf(th, "#define Air%d (sizeof(P%d) - ", i, i); if (k == 0) { fprintf(th, "%d", (nBits+7)/8); @@ -802,34 +1027,78 @@ put_ptype(char *s, int i, int m0, int m1) fatal("cannot happen Air %s", LstSet->name); } -done: fprintf(th, ")\n"); +done: fprintf(th, ")\n\n"); } } static void tc_predef_np(void) -{ int i = nrRdy; /* 1+ highest proctype nr */ +{ + fprintf(th, "#define _NP_ %d\n", nrRdy); /* 1+ highest proctype nr */ - fprintf(th, "#define _NP_ %d\n", i); -/* if (separate == 2) fprintf(th, "extern "); */ - fprintf(th, "uchar reached%d[3]; /* np_ */\n", i); + fprintf(th, "#define _nstates%d 3 /* np_ */\n", nrRdy); + fprintf(th, "#define _endstate%d 2 /* np_ */\n\n", nrRdy); + fprintf(th, "#define _start%d 0 /* np_ */\n", nrRdy); - fprintf(th, "#define nstates%d 3 /* np_ */\n", i); - fprintf(th, "#define endstate%d 2 /* np_ */\n\n", i); - fprintf(th, "#define start%d 0 /* np_ */\n", i); - - fprintf(tc, "\tcase %d: /* np_ */\n", i); + fprintf(tc, "\tcase %d: /* np_ */\n", nrRdy); if (separate == 1) - { fprintf(tc, "\t\tini_claim(%d, h);\n", i); + { fprintf(tc, "\t\tini_claim(%d, h);\n", nrRdy); } else - { fprintf(tc, "\t\t((P%d *)pptr(h))->_t = %d;\n", i, i); - fprintf(tc, "\t\t((P%d *)pptr(h))->_p = 0;\n", i); - fprintf(tc, "\t\treached%d[0] = 1;\n", i); - fprintf(tc, "\t\taccpstate[%d][1] = 1;\n", i); + { fprintf(tc, "\t\t((P%d *)pptr(h))->_t = %d;\n", nrRdy, nrRdy); + fprintf(tc, "\t\t((P%d *)pptr(h))->_p = 0;\n", nrRdy); + + fprintf(tc, "#ifdef HAS_PRIORITY\n"); + fprintf(tc, "\t\t((P%d *)pptr(h))->_priority = priority;\n", nrRdy); + fprintf(tc, "#endif\n"); + + fprintf(tc, "\t\treached%d[0] = 1;\n", nrRdy); + fprintf(tc, "\t\taccpstate[%d][1] = 1;\n", nrRdy); } fprintf(tc, "\t\tbreak;\n"); } +static void +multi_init(void) +{ ProcList *p; + Element *e; + int i = nrRdy+1; + int ini, j; + int nrc = nclaims; + + fprintf(tc, "#ifndef NOCLAIM\n"); + fprintf(tc, "\tcase %d: /* claim select */\n", i); + for (p = rdy, j = 0; p; p = p->nxt, j++) + { if (p->b == N_CLAIM) + { e = p->s->frst; + ini = huntele(e, e->status, -1)->seqno; + + fprintf(tc, "\t\tspin_c_typ[%d] = %d; /* %s */\n", + j, p->tn, p->n->name); + fprintf(tc, "\t\t((P%d *)pptr(h))->c_cur[%d] = %d;\n", + i, j, ini); + fprintf(tc, "\t\treached%d[%d]=1;\n", p->tn, ini); + + /* the default initial claim is first one in model */ + if (--nrc == 0) + { fprintf(tc, "\t\t((P%d *)pptr(h))->_t = %d;\n", i, p->tn); + fprintf(tc, "\t\t((P%d *)pptr(h))->_p = %d;\n", i, ini); + fprintf(tc, "\t\t((P%d *)pptr(h))->_n = %d; /* %s */\n", + i, j, p->n->name); + fprintf(tc, "\t\tsrc_claim = src_ln%d;\n", p->tn); + fprintf(tc, "#ifndef BFS\n"); + fprintf(tc, "\t\tif (whichclaim == -1 && claimname == NULL)\n"); + fprintf(tc, "\t\t\tprintf(\"0: Claim %s (%d), from state %d\\n\");\n", + p->n->name, p->tn, ini); + fprintf(tc, "#endif\n"); + } + } } + fprintf(tc, "\t\tif (whichclaim != -1)\n"); + fprintf(tc, "\t\t{ select_claim(whichclaim);\n"); + fprintf(tc, "\t\t}\n"); + fprintf(tc, "\t\tbreak;\n\n"); + fprintf(tc, "#endif\n"); +} + static void put_pinit(ProcList *P) { Lextok *fp, *fpt, *t; @@ -839,29 +1108,36 @@ put_pinit(ProcList *P) int i = P->tn; int ini, j, k; - if (i == claimnr + if (pid_is_claim(i) && separate == 1) { fprintf(tc, "\tcase %d: /* %s */\n", i, s->name); fprintf(tc, "\t\tini_claim(%d, h);\n", i); fprintf(tc, "\t\tbreak;\n"); return; } - if (i != claimnr + if (!pid_is_claim(i) && separate == 2) return; 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); + fprintf(th, "#define _start%d %d\n", i, ini); if (i == eventmapnr) fprintf(th, "#define start_event %d\n", ini); fprintf(tc, "\tcase %d: /* %s */\n", i, s->name); fprintf(tc, "\t\t((P%d *)pptr(h))->_t = %d;\n", i, i); - fprintf(tc, "\t\t((P%d *)pptr(h))->_p = %d;", i, ini); - fprintf(tc, " reached%d[%d]=1;\n", i, ini); + fprintf(tc, "\t\t((P%d *)pptr(h))->_p = %d;\n", i, ini); + fprintf(tc, "#ifdef HAS_PRIORITY\n"); + + fprintf(tc, "\t\t((P%d *)pptr(h))->_priority = priority; /* was: %d */\n", + i, (P->priority<1)? 1 : P->priority); + + fprintf(tc, "#endif\n"); + fprintf(tc, "\t\treached%d[%d]=1;\n", i, ini); + if (P->b == N_CLAIM) + { fprintf(tc, "\t\tsrc_claim = src_ln%d;\n", i); + } if (has_provided) { fprintf(tt, "\tcase %d: /* %s */\n\t\t", i, s->name); @@ -879,7 +1155,7 @@ put_pinit(ProcList *P) for (fp = p, j=0; fp; fp = fp->rgt) for (fpt = fp->lft; fpt; fpt = fpt->rgt, j++) { t = (fpt->ntyp == ',') ? fpt->lft : fpt; - if (t->sym->nel != 1) + if (t->sym->nel > 1 || t->sym->isarray) { lineno = t->ln; Fname = t->fn; fatal("array in parameter list, %s", @@ -898,10 +1174,10 @@ put_pinit(ProcList *P) 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, P->b); 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, P->b); fprintf(tc, "#endif\n"); } @@ -929,17 +1205,19 @@ huntstart(Element *f) } } if (cnt >= 200 || !e) - fatal("confusing control structure", (char *) 0); + { lineno = (f && f->n)?f->n->ln:lineno; + fatal("confusing control. structure", (char *) 0); + } return e; } Element * -huntele(Element *f, int o, int stopat) +huntele(Element *f, unsigned int o, int stopat) { Element *g, *e = f; int cnt=0; /* a precaution against loops */ if (e) - for (cnt = 0; cnt < 200 && e->n; cnt++) + for ( ; cnt < 500 && e->n; cnt++) { if (e->seqno == stopat) break; @@ -947,6 +1225,10 @@ huntele(Element *f, int o, int stopat) switch (e->n->ntyp) { case GOTO: g = get_lab(e->n,1); + if (e == g) + { lineno = (f && f->n)?f->n->ln:lineno; + fatal("infinite goto loop", (char *) 0); + } cross_dsteps(e->n, g->n); break; case '.': @@ -957,6 +1239,9 @@ huntele(Element *f, int o, int stopat) break; case UNLESS: g = huntele(e->sub->this->frst, o, stopat); + if (!g) + { fatal("unexpected error 1", (char *) 0); + } break; case D_STEP: case ATOMIC: @@ -968,8 +1253,10 @@ huntele(Element *f, int o, int stopat) return e; e = g; } - if (cnt >= 200 || !e) + if (cnt >= 500 || !e) + { lineno = (f && f->n)?f->n->ln:lineno; fatal("confusing control structure", (char *) 0); + } return e; } @@ -992,7 +1279,7 @@ typ2c(Symbol *sp) nBits += sp->nbits; break; case BIT: - if (sp->nel == 1 && !(sp->hidden&1)) + if (sp->nel == 1 && sp->isarray == 0 && !(sp->hidden&1)) { fprintf(th, "\tunsigned %s : 1", sp->name); LstSet = sp; nBits++; @@ -1031,13 +1318,13 @@ typ2c(Symbol *sp) fatal("variable %s undeclared", sp->name); } - if (sp->nel != 1) + if (sp->nel > 1 || sp->isarray) fprintf(th, "[%d]", sp->nel); fprintf(th, ";\n"); } static void -ncases(FILE *fd, int p, int n, int m, char *c[]) +ncases(FILE *fd, int p, int n, int m, const char *c[]) { int i, j; for (j = 0; c[j]; j++) @@ -1067,12 +1354,11 @@ genaddqueue(void) 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) @@ -1124,6 +1410,22 @@ genaddqueue(void) ntimes(tc, 0, 1, Addq1); + fprintf(tc, "#ifdef TRIX\n"); + fprintf(tc, "int\nwhat_p_size(int t)\n{\tint j;\n"); + fprintf(tc, " switch (t) {\n"); + ntimes(tc, 0, nrRdy+1, R5); /* +1 for np_ */ + fprintf(tc, " default: Uerror(\"bad proctype\");\n"); + fprintf(tc, " }\n return j;\n}\n\n"); + + fprintf(tc, "int\nwhat_q_size(int t)\n{\tint j;\n"); + fprintf(tc, " switch (t) {\n"); + for (j = 0; j < nqs+1; j++) + { fprintf(tc, " case %d: j = sizeof(Q%d); break;\n", j, j); + } + fprintf(tc, " default: Uerror(\"bad qtype\");\n"); + fprintf(tc, " }\n return j;\n}\n"); + fprintf(tc, "#endif\n\n"); + if (has_random) { fprintf(th, "int Q_has(int"); for (j = 0; j < Mpars; j++) @@ -1159,7 +1461,7 @@ genaddqueue(void) fprintf(tc, "void\nqsend(int into, int sorted"); for (j = 0; j < Mpars; j++) fprintf(tc, ", int fld%d", j); - fprintf(tc, ")\n"); + fprintf(tc, ", int args_given)\n"); ntimes(tc, 0, 1, Addq11); for (q = qtab; q; q = q->nxt) @@ -1202,6 +1504,12 @@ genaddqueue(void) sprintf(buf0, "((Q%d *)z)->contents[j].fld", q->qid); for (j = 0; j < q->nflds; j++) fprintf(tc, "\t\t%s%d = fld%d;\n", buf0, j, j); + fprintf(tc, "\t\tif (args_given != %d)\n", q->nflds); + fprintf(tc, "\t\t{ if (args_given > %d)\n", q->nflds); + fprintf(tc, "\t\t uerror(\"too many parameters in send stmnt\");\n"); + fprintf(tc, "\t\t else\n"); + fprintf(tc, "\t\t uerror(\"too few parameters in send stmnt\");\n"); + fprintf(tc, "\t\t}\n"); fprintf(tc, "\t\tbreak;\n"); } ntimes(tc, 0, 1, Addq2); @@ -1261,14 +1569,15 @@ genaddqueue(void) fprintf(tc, " case %d: j = sizeof(Q%d); break;\n", q->qid, q->qid); ntimes(tc, 0, 1, R8b); + ntimes(th, 0, 1, Proto); /* function prototypes */ - ntimes(th, 0, 1, Proto); /* tag on function prototypes */ fprintf(th, "void qsend(int, int"); for (j = 0; j < Mpars; j++) fprintf(th, ", int"); - fprintf(th, ");\n"); + fprintf(th, ", int);\n\n"); - fprintf(th, "#define Addproc(x) addproc(x"); + fprintf(th, "#define Addproc(x,y) addproc(256, y, x"); + /* 256 is param outside the range of valid pids */ for (j = 0; j < Npars; j++) fprintf(th, ", 0"); fprintf(th, ")\n"); diff --git a/sys/src/cmd/spin/pangen1.h b/sys/src/cmd/spin/pangen1.h index 81facb646..e09930eec 100644 --- a/sys/src/cmd/spin/pangen1.h +++ b/sys/src/cmd/spin/pangen1.h @@ -1,20 +1,56 @@ /***** spin: pangen1.h *****/ -/* Copyright (c) 1989-2005 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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ -static char *Code2a[] = { /* the tail of procedure run() */ - "#if defined(VERI) && !defined(NOREDUCE) && !defined(NP)", - " if (!state_tables", - "#ifdef HAS_CODE", - " && !readtrail", +static const char *Code2a[] = { /* the tail of procedure run() */ + " if (state_tables)", + " { if (dodot) exit(0);", + " printf(\"\\nTransition Type: \");", + " printf(\"A=atomic; D=d_step; L=local; G=global\\n\");", + " printf(\"Source-State Labels: \");", + " printf(\"p=progress; e=end; a=accept;\\n\");", + "#ifdef MERGED", + " printf(\"Note: statement merging was used. Only the first\\n\");", + " printf(\" stmnt executed in each merge sequence is shown\\n\");", + " printf(\" (use spin -a -o3 to disable statement merging)\\n\");", "#endif", + " pan_exit(0);", + " }", + "#if defined(BFS) && defined(TRIX)", /* before iniglobals */ + " { int i;", + " for (i = 0; i < MAXPROC+1; i++)", + " { processes[i] = (TRIX_v6 *) emalloc(sizeof(TRIX_v6));", + " processes[i]->body = (uchar *) emalloc(Maxbody * sizeof(char));", + " }", + " for (i = 0; i < MAXQ+1; i++)", + " { channels[i] = (TRIX_v6 *) emalloc(sizeof(TRIX_v6));", + " channels[i]->body = (uchar *) emalloc(Maxbody * sizeof(char));", + " } }", + "#endif", + "#ifdef BFS_PAR", + " bfs_setup_mem();", + " #ifdef COLLAPSE", + " /* this must be the very first allocation from the shared heap */", + " #ifdef BFS_SEP_HASH", + " ncomps = (ulong *) emalloc((ulong)((256+2) * sizeof(ulong)));", + " #else", + " ncomps = (ulong *) sh_pre_malloc((ulong)((256+2) * sizeof(ulong)));", + " #endif", + " #endif", + "#endif", + " iniglobals(258); /* arg outside range of pids */", + "#if defined(VERI) && !defined(NOREDUCE) && !defined(NP) && !defined(BFS) && !defined(HAS_LTL)", + " if (!state_tables", + " #ifdef HAS_CODE", + " && !readtrail", + " #endif", + " #if NCORE>1", + " && core_id == 0", + " #endif", " )", " { printf(\"warning: for p.o. reduction to be valid \");", " printf(\"the never claim must be stutter-invariant\\n\");", @@ -24,14 +60,7 @@ static char *Code2a[] = { /* the tail of procedure run() */ "#endif", " UnBlock; /* disable rendez-vous */", "#ifdef BITSTATE", -#ifndef POWOW - " if (udmem)", - " { udmem *= 1024L*1024L;", - " SS = (uchar *) emalloc(udmem);", - " bstore = bstore_mod;", - " } else", -#endif - " SS = (uchar *) emalloc(1L<<(ssize-3));", + " sinit();", "#else", " hinit();", "#endif", @@ -39,18 +68,24 @@ static char *Code2a[] = { /* the tail of procedure run() */ " onstack_init();", "#endif", "#if defined(CNTRSTACK) && !defined(BFS)", - " LL = (uchar *) emalloc(1L<<(ssize-3));", + " LL = (uchar *) emalloc(ONE_L<<(ssize-3));", "#endif", - " stack = ( Stack *) emalloc(sizeof(Stack));", + " stack = (_Stack *) emalloc(sizeof(_Stack));", " svtack = (Svtack *) emalloc(sizeof(Svtack));", " /* a place to point for Pptr of non-running procs: */", - " noptr = (uchar *) emalloc(Maxbody * sizeof(char));", - "#ifdef SVDUMP", + " noqptr = noptr = (uchar *) emalloc(Maxbody * sizeof(char));", + "#if defined(SVDUMP) && defined(VERBOSE)", " if (vprefix > 0)", - " write(svfd, (uchar *) &vprefix, sizeof(int));", + " (void) write(svfd, (uchar *) &vprefix, sizeof(int));", "#endif", "#ifdef VERI", - " Addproc(VERI); /* never - pid = 0 */", + " Addproc(VERI,1); /* pid = 0, priority 1 */", + " #if NCLAIMS>1", + " if (claimname != NULL)", + " { whichclaim = find_claim(claimname);", + " select_claim(whichclaim);", + " }", + " #endif", "#endif", " active_procs(); /* started after never */", "#ifdef EVENT_TRACE", @@ -66,17 +101,21 @@ static char *Code2a[] = { /* the tail of procedure run() */ "#endif", " do_the_search();", "#ifdef BITSTATE", - " if (--Nrun > 0 && HASH_CONST[++HASH_NR])", + " if (--Nrun > 0 && HASH_CONST[++HASH_NR])", /* last entry is 0 */ " { printf(\"Run %%d:\\n\", HASH_NR);", " wrap_stats();", " printf(\"\\n\");", - " memset(SS, 0, 1L<<(ssize-3));", - "#if defined(CNTRSTACK)", - " memset(LL, 0, 1L<<(ssize-3));", + " if (udmem) /* Dillinger 3/2/09 */", + " { memset(SS, 0, udmem);", + " } else", + " { memset(SS, 0, ONE_L<<(ssize-3));", + " }", + "#ifdef CNTRSTACK", + " memset(LL, 0, ONE_L<<(ssize-3));", "#endif", - "#if defined(FULLSTACK)", + "#ifdef FULLSTACK", " memset((uchar *) S_Tab, 0, ", - " maxdepth*sizeof(struct H_el *));", + " maxdepth*sizeof(H_el *));", "#endif", " nstates=nlinks=truncs=truncs2=ngrabs = 0;", " nlost=nShadow=hcmp = 0;", @@ -86,8 +125,157 @@ static char *Code2a[] = { /* the tail of procedure run() */ " }", "#endif", "}", + "#ifdef HAS_PRIORITY", + "extern int highest_priority(int, short, Trans *);", + "extern int get_priority(int);", + "extern int set_priority(int, int);", + "#endif", + "#ifdef SPIN_HEAP", + "void *", + "spin_malloc(int n) /* reserved for use by Modex generated models */", + "{ char *spin_heap_ptr = &(now.spin_heap[now.spin_heap_n]);", + " if (now.spin_heap_n + n >= sizeof(now.spin_heap))", + " { Uerror(\"spin_heap limit reached\");", + " }", + " now.spin_heap_n += n;", + " return spin_heap_ptr;", + "}", + "void", + "spin_free(void *unused)", + "{ unused; /* ignore */", + "}", + "#endif", + "int", + "spin_join(int p, void **unused)", + "{ /* fprintf(stderr, \"join %%d when %%d\\n \", p, now._nr_pr); */", + " return (now._nr_pr <= p); /* process *p has stopped */", + "}", + "", + "int", + "spin_mutex_free(int *m)", + "{ return (*m == 0);", + "}", + "", + "int", + "spin_mutex_lock(int *m)", + "{ *m = 1;", + " return 1;", + "}", + "void", + "spin_mutex_destroy(int *m)", + "{ *m = 0;", + "}", + "void", + "spin_mutex_unlock(int *m)", + "{ *m = 0;", + "}", + "void", + "spin_mutex_init(int *m, void *val)", + "{", + " if (!val)", /* the 2nd arg must be NULL, for now */ + " { *m = 0;", + " } else", + " { Uerror(\"pthread_mutex_init: unsupported non-default init\");", + " }", + "}", + "", + "int", + "spin_cond_wait(int *cond, int *lck)", /*release and re-acquire lock *lck */ + "{ /* this version does not scale very far alas */", + " if (((P0 *)this)->_pid + 1 >= WS*8)", /* 32 or 64 */ + " { Uerror(\"pid exceeds range supported by pthread_cond_wait\");", + " }", + " if (((*cond)&1) == 0)", /* repeatedly tested, so: */ + " { spin_mutex_unlock(lck);", /* avoid double counting */ + " *cond |= (1<<(((P0 *)this)->_pid + 1));", + " return 0;", /* blocked, must test again */ + " } else", + " { /* if other processes are already waiting */", + " /* while our wait flag is 0, then they should go first */", + " if (((*cond)&(~(1 | (1<<(((P0 *)this)->_pid + 1))))) != 0)", + " { spin_mutex_unlock(lck);", + " return 0;", /* wait for the others to go first */ + " }", + " *cond &= ~1;", /* clear the 'go' bit andy wait flag */ + " *cond &= ~(1<<(((P0 *)this)->_pid + 1));", + " return 1;", /* okay to proceed */ + " }", + "}", + "void", + "spin_cond_signal(int *cond)", + "{", + " if ( ((*cond)&(~1)) != 0 )", /* procs are waiting */ + " { *cond |= 1;", /* set the 'go' bit */ + " }", + "}", + "", "#ifdef HAS_PROVIDED", - "int provided(int, uchar, int, Trans *);", + " int provided(int, uchar, int, Trans *);", + "#endif", + "#ifdef BFS_PAR", + " extern void bfs_shutdown(const char *);", + "#endif", + "", + "#if NCORE>1", + " #define GLOBAL_LOCK (0)", + " #ifndef CS_N", + " #define CS_N (256*NCORE)", /* must be a power of 2 */ + " #endif", + + " #ifdef NGQ", /* no global queue */ + " #define NR_QS (NCORE)", + " #define CS_NR (CS_N+1) /* 2^N + 1, nr critical sections */", + " #define GQ_RD GLOBAL_LOCK", /* not really used in this mode */ + " #define GQ_WR GLOBAL_LOCK", /* but just in case... */ + " #define CS_ID (1 + (int) (j1_spin & (CS_N-1))) /* mask: 2^N - 1, zero reserved */", + " #define QLOCK(n) (1+n)", /* overlaps first n zones of hashtable */ + " #else", + " #define NR_QS (NCORE+1)", /* add a global queue */ + " #define CS_NR (CS_N+3)", /* 2 extra locks for global q */ + " #define GQ_RD (1)", /* read access to global q */ + " #define GQ_WR (2)", /* write access to global q */ + " #define CS_ID (3 + (int) (j1_spin & (CS_N-1)))", + " #define QLOCK(n) (3+n)",/* overlaps first n zones of hashtable */ + " #endif", + "", + " #ifndef SEP_STATE", + " #define enter_critical(w) e_critical(w)", + " #define leave_critical(w) x_critical(w)", + " #else", + " #ifdef NGQ", + " #define enter_critical(w) { if (w < 1+NCORE) e_critical(w); }", + " #define leave_critical(w) { if (w < 1+NCORE) x_critical(w); }", + " #else", + " #define enter_critical(w) { if (w < 3+NCORE) e_critical(w); }", + " #define leave_critical(w) { if (w < 3+NCORE) x_critical(w); }", + " #endif", + " #endif", + "", + " int", + " cpu_printf(const char *fmt, ...)", /* only used with VERBOSE/CHECK/DEBUG */ + " { va_list args;", + " enter_critical(GLOBAL_LOCK); /* printing */", + " printf(\"cpu%%d: \", core_id);", + " fflush(stdout);", + " va_start(args, fmt);", + " vprintf(fmt, args);", + " va_end(args);", + " fflush(stdout);", + " leave_critical(GLOBAL_LOCK);", + " return 1;", + " }", + "#else", + " #define enter_critical(w) /* none */", + " #define leave_critical(w) /* none */", + "", + " int", + " cpu_printf(const char *fmt, ...)", + " { va_list args;", + " va_start(args, fmt);", + " vprintf(fmt, args);", + " va_end(args);", + " return 1;", + " }", "#endif", #ifndef PRINTF @@ -132,7 +320,7 @@ static char *Code2a[] = { /* the tail of procedure run() */ "static int stackread;", "static Trail frameptr;", "Trail *", - "getframe(int d)", + "getframe(long d)", "{", " if (CNT1 == CNT2)", " return &trail[d];", @@ -153,63 +341,103 @@ static char *Code2a[] = { /* the tail of procedure run() */ " return &frameptr;", "}", "#endif", - - "#if !defined(SAFETY) && !defined(BITSTATE)", - "#if !defined(FULLSTACK) || defined(MA)", - "#define depth_of(x) A_depth /* an estimate */", - "#else", - "int", - "depth_of(struct H_el *s)", - "{ Trail *t; int d;", - " for (d = 0; d <= A_depth; d++)", - " { t = getframe(d);", - " if (s == t->ostate)", - " return d;", - " }", - " printf(\"pan: cannot happen, depth_of\\n\");", - " return depthfound;", - "}", + "#if NCORE>1", + "extern void cleanup_shm(int);", + "volatile uint *search_terminated; /* to signal early termination */", + /* + * Meaning of bitflags in search_terminated: + * 1 set by pan_exit + * 2 set by wrapup + * 4 set by uerror + * 8 set by sudden_stop -- called after someone_crashed and [Uu]error + * 16 set by cleanup_shm + * 32 set by give_up -- called on signal + * 64 set by proxy_exit + * 128 set by proxy on write port failure + * 256 set by proxy on someone_crashed + * + * Flags 8|32|128|256 indicate abnormal termination + * + * The flags are checked in 4 functions in the code: + * sudden_stop() + * someone_crashed() (proxy and pan version) + * mem_hand_off() + */ "#endif", - "#endif", - "void", "pan_exit(int val)", - "{ if (signoff) printf(\"--end of output--\\n\");", + "{ void stop_timer(int);", + "#ifdef BFS_PAR", + " extern void bfs_mark_done(int);", + " extern void bfs_drop_shared_memory(void);", + "#endif", + " if (signoff)", + " { printf(\"--end of output--\\n\");", + " }", + "#if NCORE>1", + " if (search_terminated != NULL)", + " { *search_terminated |= 1; /* pan_exit */", + " }", + "#ifdef USE_DISK", + " { void dsk_stats(void);", + " dsk_stats();", + " }", + "#endif", + " if (!state_tables && !readtrail)", + " { cleanup_shm(1);", + " }", + "#endif", + "#ifdef BFS_PAR", + " if (who_am_i != 0)", + " { bfs_mark_done(3); /* stopped */", + " }", + " bfs_drop_shared_memory();", + "#endif", + " if (val == 2)", + " { val = 0;", + " }", + "#ifdef BFS_PAR", + " if (who_am_i == 0)", + "#endif", + " stop_timer(1);", + "", + "#ifdef C_EXIT", + " C_EXIT; /* trust that it defines a fct */", + "#endif", " exit(val);", "}", - "#ifdef HAS_CODE", + "static char tbuf[2][2048];", + "", "char *", "transmognify(char *s)", "{ char *v, *w;", - " static char buf[2][2048];", " int i, toggle = 0;", - " if (!s || 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 */ + " memset(tbuf[0], 0, 2048);", + " memset(tbuf[1], 0, 2048);", + " strcpy(tbuf[toggle], s);", + " while ((v = strstr(tbuf[toggle], \"{c_code\")))", /* assign v */ " { *v = '\\0'; v++;", - " strcpy(buf[1-toggle], buf[toggle]);", + " strcpy(tbuf[1-toggle], tbuf[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])", + " { if (strlen(tbuf[1-toggle])", " + strlen(code_lookup[i].t)", " + strlen(w) > 2047)", " return s;", - " strcat(buf[1-toggle], code_lookup[i].t);", + " strcat(tbuf[1-toggle], code_lookup[i].t);", " break;", " }", - " strcat(buf[1-toggle], w);", + " strcat(tbuf[1-toggle], w);", " toggle = 1 - toggle;", " }", - " buf[toggle][2047] = '\\0';", - " return buf[toggle];", + " tbuf[toggle][2047] = '\\0';", + " return tbuf[toggle];", "}", "#else", "char * transmognify(char *s) { return s; }", @@ -223,7 +451,6 @@ static char *Code2a[] = { /* the tail of procedure run() */ "", " for (t = trans[ot][tt]; t; t = t->nxt)", " { printf(\"\\t\\t\");", - " q = transmognify(t->tp);", " for ( ; q && *q; q++)", " if (*q == '\\n')", @@ -233,6 +460,17 @@ static char *Code2a[] = { /* the tail of procedure run() */ " printf(\"\\n\");", " }", "}", + "", + "char *", + "find_source(int tp, int s)", + "{", + " if (s >= flref[tp]->from", + " && s <= flref[tp]->upto)", + " { return flref[tp]->fnm;", + " }", + " return PanSource; /* i.e., don't know */", + "}", + "", "void", "wrap_trail(void)", "{ static int wrap_in_progress = 0;", @@ -243,14 +481,15 @@ static char *Code2a[] = { /* the tail of procedure run() */ "", " printf(\"spin: trail ends after %%ld steps\\n\", depth);", " if (onlyproc >= 0)", - " { if (onlyproc >= now._nr_pr) pan_exit(0);", + " { if (onlyproc >= now._nr_pr) { pan_exit(0); }", " II = onlyproc;", " z = (P0 *)pptr(II);", " printf(\"%%3ld:\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\",", + " { printf(\" %%s:%%d\",", + " find_source((int) z->_t, (int) z->_p),", " src_all[i].src[z->_p]);", " break;", " }", @@ -269,7 +508,8 @@ static char *Code2a[] = { /* the tail of procedure run() */ " depth, II, procname[z->_t]);", " for (i = 0; src_all[i].src; i++)", " if (src_all[i].tp == (int) z->_t)", - " { printf(\" line %%3d\",", + " { printf(\" %%s:%%d\",", + " find_source((int) z->_t, (int) z->_p),", " src_all[i].src[z->_p]);", " break;", " }", @@ -293,23 +533,100 @@ static char *Code2a[] = { /* the tail of procedure run() */ "findtrail(void)", "{ FILE *fd;", " char fnm[512], *q;", - " char MyFile[512];", + " char MyFile[512];", /* avoid using a non-writable string */ + " char MySuffix[16];", + " int try_core;", + " int candidate_files;", "", - " strcpy(MyFile, TrailFile);", /* avoid problem with non-writable strings */ + " if (trailfilename != NULL)", + " { fd = fopen(trailfilename, \"r\");", + " if (fd == NULL)", + " { printf(\"pan: cannot find %%s\\n\", trailfilename);", + " pan_exit(1);", + " } /* else */", + " goto success;", + " }", + "talk:", + " try_core = 1;", + " candidate_files = 0;", + " tprefix = \"trail\";", + " strcpy(MyFile, TrailFile);", + " do { /* see if there's more than one possible trailfile */", + " if (whichtrail)", + " { sprintf(fnm, \"%%s%%d.%%s\",", + " MyFile, whichtrail, tprefix);", + " fd = fopen(fnm, \"r\");", + " if (fd != NULL)", + " { candidate_files++;", + " if (verbose==100)", + " printf(\"trail%%d: %%s\\n\",", + " candidate_files, fnm);", + " fclose(fd);", + " }", + " if ((q = strchr(MyFile, \'.\')) != NULL)", + " { *q = \'\\0\';", /* e.g., strip .pml */ + " sprintf(fnm, \"%%s%%d.%%s\",", + " MyFile, whichtrail, tprefix);", + " *q = \'.\';", + " fd = fopen(fnm, \"r\");", + " if (fd != NULL)", + " { candidate_files++;", + " if (verbose==100)", + " printf(\"trail%%d: %%s\\n\",", + " candidate_files, fnm);", + " fclose(fd);", + " } }", + " } else", + " { sprintf(fnm, \"%%s.%%s\", MyFile, tprefix);", + " fd = fopen(fnm, \"r\");", + " if (fd != NULL)", + " { candidate_files++;", + " if (verbose==100)", + " printf(\"trail%%d: %%s\\n\",", + " candidate_files, fnm);", + " fclose(fd);", + " }", + " if ((q = strchr(MyFile, \'.\')) != NULL)", + " { *q = \'\\0\';", /* e.g., strip .pml */ + " sprintf(fnm, \"%%s.%%s\", MyFile, tprefix);", + " *q = \'.\';", + " fd = fopen(fnm, \"r\");", + " if (fd != NULL)", + " { candidate_files++;", + " if (verbose==100)", + " printf(\"trail%%d: %%s\\n\",", + " candidate_files, fnm);", + " fclose(fd);", + " } } }", + " tprefix = MySuffix;", + " sprintf(tprefix, \"cpu%%d_trail\", try_core++);", + " } while (try_core <= NCORE);", "", + " if (candidate_files != 1)", + " { if (verbose != 100)", + " { printf(\"error: there are %%d trail files:\\n\",", + " candidate_files);", + " verbose = 100;", + " goto talk;", + " } else", + " { printf(\"pan: rm or mv all except one\\n\");", + " exit(1);", + " } }", + + " try_core = 1;", + " strcpy(MyFile, TrailFile); /* restore */", + " tprefix = \"trail\";", + "try_again:", " if (whichtrail)", " { sprintf(fnm, \"%%s%%d.%%s\", MyFile, whichtrail, tprefix);", " fd = fopen(fnm, \"r\");", " if (fd == NULL && (q = strchr(MyFile, \'.\')))", " { *q = \'\\0\';", /* e.g., strip .pml on original file */ - " sprintf(fnm, \"%%s%%d.%%s\", MyFile, whichtrail, tprefix);", + " sprintf(fnm, \"%%s%%d.%%s\",", + " MyFile, whichtrail, tprefix);", " *q = \'.\';", " fd = fopen(fnm, \"r\");", - " if (fd == NULL)", - " { printf(\"pan: cannot find %%s%%d.%%s or %%s\\n\", ", - " MyFile, whichtrail, tprefix, fnm);", - " pan_exit(1);", - " } }", + " }", " } else", " { sprintf(fnm, \"%%s.%%s\", MyFile, tprefix);", " fd = fopen(fnm, \"r\");", @@ -318,56 +635,122 @@ static char *Code2a[] = { /* the tail of procedure run() */ " sprintf(fnm, \"%%s.%%s\", MyFile, tprefix);", " *q = \'.\';", " fd = fopen(fnm, \"r\");", - " if (fd == NULL)", - " { printf(\"pan: cannot find %%s.%%s or %%s\\n\", ", - " MyFile, tprefix, fnm);", - " pan_exit(1);", - " } } }", + " } }", " if (fd == NULL)", - " { printf(\"pan: cannot find trailfile %%s\\n\", fnm);", + " { if (try_core < NCORE)", + " { tprefix = MySuffix;", + " sprintf(tprefix, \"cpu%%d_trail\", try_core++);", + " goto try_again;", + " }", + " printf(\"pan: cannot find trailfile %%s\\n\", fnm);", " pan_exit(1);", " }", + "success:", + "#if NCORE>1 && defined(SEP_STATE)", + " { void set_root(void); /* for partial traces from local root */", + " set_root();", + " }", + "#endif", " return fd;", "}", "", "uchar do_transit(Trans *, short);", + "#ifdef PERMUTED", + "void set_permuted(int);", + "void set_reversed(int);", + "void set_rotated(int);", + "void set_randrot(int);", + "void (*p_reorder)(int) = set_permuted;", + "short p_rotate;", + "#endif", "", "void", "getrail(void)", "{ FILE *fd;", - " char *q;", - " int i, t_id, lastnever=-1; short II;", + " char *q, *pnm;", + " int i, t_id, lastnever = -1; short II;", " Trans *t;", " P0 *z;", - "", + "#ifdef PERMUTED", + " char sbuf[128];", + " memset(sbuf, 0, sizeof(sbuf));", + "#endif", " fd = findtrail(); /* exits if unsuccessful */", " while (fscanf(fd, \"%%ld:%%d:%%d\\n\", &depth, &i, &t_id) == 3)", " { if (depth == -1)", - " printf(\"<<<<>>>>\\n\");", + " { printf(\"<<<<>>>>\\n\");", + " }", + "#ifdef PERMUTED", " if (depth < 0)", - " continue;", + " { switch (depth) {", + " case -5:", + " if (i && !t_reverse)", + " { strcat(sbuf, \"-t_reverse \");", + " }", + " break;", + " case -6:", + " if (i && p_reorder != set_permuted)", + " { strcat(sbuf, \"-p_permute \");", + " } else", + " if (t_id && p_reorder != set_reversed)", + " { strcat(sbuf, \"-p_reverse \");", + " }", + " break;", + " case -7:", + " if (i", + " && (p_reorder != set_rotated || p_rotate != t_id))", + " { char tmp[32];", + " sprintf(tmp, \"-p_rotate%%d \", t_id);", + " strcat(sbuf, tmp);", + " }", + " break;", + " case -8:", + " if (i && p_reorder != set_randrot)", + " { strcat(sbuf, \"-p_randrot \");", + " }", + " if (s_rand != ++t_id)", + " { char tmp[32];", + " sprintf(tmp, \"-RS%%u \", (uint) t_id-1);", + " strcat(sbuf, tmp);", + " }", + " break;", + " default:", + " continue;", + " }", + " }", + "#endif", + " if (depth < 0)", + " { continue;", + " }", + "#ifdef PERMUTED", + " if (strlen(sbuf) > 0)", + " { fprintf(efd, \"add: %%s\\n\", sbuf);", + " exit(1);", + " }", + "#endif", " if (i > now._nr_pr)", " { printf(\"pan: Error, proc %%d invalid pid \", i);", " printf(\"transition %%d\\n\", t_id);", " break;", " }", " II = i;", - "", " z = (P0 *)pptr(II);", " for (t = trans[z->_t][z->_p]; t; t = t->nxt)", - " if (t->t_id == t_id)", + " if (t->t_id == (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);", + " if (t && t->t_id == (T_ID) t_id)", + " { printf(\"\\tRecovered 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);", + " printf(\"pan: list of possible transitions in this process:\\n\");", + " if (z->_t >= 0 && z->_t <= _NP_)", " 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);", @@ -377,11 +760,13 @@ static char *Code2a[] = { /* the tail of procedure run() */ " q = transmognify(t->tp);", " if (gui) simvals[0] = \'\\0\';", + " pnm = procname[z->_t];", " this = pptr(II);", " trpt->tau |= 1;", /* timeout always possible */ " if (!do_transit(t, II))", " { if (onlyproc >= 0 && II != onlyproc)", " goto moveon;", + " if (!verbose) break;", " 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\");", @@ -391,16 +776,24 @@ static char *Code2a[] = { /* the tail of procedure run() */ " goto moveon;", " if (verbose)", - " { printf(\"depth: %%3ld proc: %%3d trans: %%3d (%%d procs) \",", - " depth, II, t_id, now._nr_pr);", - " printf(\"forw=%%3d [%%s]\\n\", t->forw, q);", - "", + " { printf(\"%%3ld: proc %%2d (%%s) \", depth, II, pnm);", + + " for (i = 0; src_all[i].src; i++)", + " if (src_all[i].tp == (int) z->_t)", + " { printf(\" %%s:%%d \",", + " find_source((int) z->_t, (int) z->_p),", + " src_all[i].src[z->_p]);", + " break;", + " }", + + " printf(\"(state %%d) trans {%%d,%%d} [%%s]\\n\",", + " z->_p, t_id, t->forw, q?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)", + " } else if (Btypes[z->_t] == N_CLAIM)", " { if (lastnever != (int) z->_p)", " { for (i = 0; src_all[i].src; i++)", " if (src_all[i].tp == (int) z->_t)", @@ -413,38 +806,39 @@ static char *Code2a[] = { /* the tail of procedure run() */ " }", " lastnever = z->_p;", " goto sameas;", - " } else", - " if (strcmp(procname[z->_t], \":np_:\") != 0)", + " } else if (Btypes[z->_t] != 0) /* not :np_: */", " {", "sameas: if (no_rck) goto moveon;", " if (coltrace)", " { printf(\"%%ld: \", depth);", " for (i = 0; i < II; i++)", " printf(\"\\t\\t\");", - " printf(\"%%s(%%d):\", procname[z->_t], II);", + " printf(\"%%s(%%d):\", pnm, II);", " printf(\"[%%s]\\n\", q?q:\"\");", " } else if (!silent)", " { if (strlen(simvals) > 0) {", " printf(\"%%3ld: proc %%2d (%%s)\", ", - " depth, II, procname[z->_t]);", + " depth, II, pnm);", " for (i = 0; src_all[i].src; i++)", " if (src_all[i].tp == (int) z->_t)", - " { printf(\" line %%3d \\\"pan_in\\\" \",", + " { printf(\" %%s:%%d \",", + " find_source((int) z->_t, (int) z->_p),", " src_all[i].src[z->_p]);", " break;", " }", " printf(\"(state %%d)\t[values: %%s]\\n\", z->_p, simvals);", " }", " printf(\"%%3ld: proc %%2d (%%s)\", ", - " depth, II, procname[z->_t]);", + " depth, II, pnm);", " for (i = 0; src_all[i].src; i++)", " if (src_all[i].tp == (int) z->_t)", - " { printf(\" line %%3d \\\"pan_in\\\" \",", + " { printf(\" %%s:%%d \",", + " find_source((int) z->_t, (int) z->_p),", " src_all[i].src[z->_p]);", " break;", " }", " printf(\"(state %%d)\t[%%s]\\n\", z->_p, q?q:\"\");", - " printf(\"\\n\");", + " /* printf(\"\\n\"); */", " } }", "moveon: z->_p = t->st;", " }", @@ -462,19 +856,22 @@ static char *Code2a[] = { /* the tail of procedure run() */ " }", " return -1;", "}", - "#ifdef VERI", - "void check_claim(int);", + "", + "#if NCORE>1 && !defined(GLOB_HEAP)", + " #define SEP_HEAP /* version 5.1.2 */", "#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;", + "{ ulong x, y;", + " uint i = 1;", + "#if defined(MURMUR) && (WS==8)", + " m_hash((uchar *) v, n); /* bstore_mod - sets j3_spin, j4_spin, K1, K2 */", + "#else", + " d_hash((uchar *) v, n); /* bstore_mod - sets j3_spin, j4_spin, K1, K2 */", + "#endif", + " x = K1; y = j3_spin;", /* was K2 before 5.1.1 */ " for (;;)", " { if (!(SS[x%%udmem]&(1< 0)", + " {", + "#ifdef PUTPID", + " sprintf(fnm, \"%%s_%%s_%%d_%%d.%%s\",", + " MyFile, progname, getpid(), Nr_Trails-1, tprefix);", + "#else", " sprintf(fnm, \"%%s%%d.%%s\",", " MyFile, Nr_Trails-1, tprefix);", - " else", + "#endif", + " } else", + " {", + "#ifdef PUTPID", + " sprintf(fnm, \"%%s_%%s_%%d.%%s\", MyFile, progname, getpid(), tprefix);", + "#else", " sprintf(fnm, \"%%s.%%s\", MyFile, tprefix);", - "", - " if ((fd = creat(fnm, TMODE)) < 0)", + "#endif", + " }", + " if ((fd = open(fnm, w_flags, TMODE)) < 0)", " { if ((q = strchr(MyFile, \'.\')))", " { *q = \'\\0\';", /* strip .pml */ " if (iterative == 0 && Nr_Trails-1 > 0)", @@ -574,91 +989,146 @@ static char *Code2a[] = { /* the tail of procedure run() */ " else", " sprintf(fnm, \"%%s.%%s\", MyFile, tprefix);", " *q = \'.\';", - " fd = creat(fnm, TMODE);", + " fd = open(fnm, w_flags, TMODE);", " } }", " if (fd < 0)", " { printf(\"pan: cannot create %%s\\n\", fnm);", " perror(\"cause\");", " } else", - " { printf(\"pan: wrote %%s\\n\", fnm);", + " {", + "#if NCORE>1 && (defined(SEP_STATE) || !defined(FULL_TRAIL))", + " void write_root(void); ", + " write_root();", + "#else", + " printf(\"pan: wrote %%s\\n\", fnm);", + "#endif", " }", " return fd;", "}", - 0 -}; + "", + "#ifndef FREQ", + "#define FREQ (1000000)", + "#endif", + "double freq = (double) FREQ;\n", -static char *Code2b[] = { /* breadth-first search option */ - "#ifdef BFS", - "#define Q_PROVISO", - "#ifndef INLINE_REV", - "#define INLINE_REV", + "#ifdef TRIX", + "void sv_populate(void);", + "", + "void", + "re_populate(void) /* restore procs and chans from now._ids_ */", + "{ int i, cnt = 0;", + " char *b;", + "#ifdef V_TRIX", + " printf(\"%%4d: re_populate\\n\", depth);", "#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;", - "#if VECTORSZ>32000", - " int *po;", - "#else", - " short *po;", + " for (i = 0; i < now._nr_pr; i++, cnt++)", + " { b = now._ids_[cnt];", + " processes[i]->psize = what_p_size( ((P0 *)b)->_t );", + " memcpy(processes[i]->body, b, processes[i]->psize);", + "#ifdef TRIX_RIX", + " ((P0 *)pptr(i))->_pid = i;", + " if (BASE > 0 && h > 0)", + " { ((P0 *)pptr(i))->_pid -= BASE;", + " }", "#endif", - " int *qo;", - " uchar *ps, *qs;", - " struct EV_Hold *nxt;", - "} EV_Hold;", - "", - "typedef struct BFS_Trail {", - " Trail *frame;", - " SV_Hold *onow;", - " EV_Hold *omask;", - "#ifdef Q_PROVISO", - " struct H_el *lstate;", + "#ifndef BFS", + " processes[i]->modified = 1; /* re-populate */", "#endif", - " short boq;", - " struct BFS_Trail *nxt;", - "} BFS_Trail;", + " }", + " for (i = 0; i < now._nr_qs; i++, cnt++)", + " { b = now._ids_[cnt];", + " channels[i]->psize = what_q_size( ((Q0 *)b)->_t );", + " memcpy(channels[i]->body, b, channels[i]->psize);", + "#ifndef BFS", + " channels[i]->modified = 1; /* re-populate */", + "#endif", + " }", + "}", + "#endif\n", + + "#ifdef BFS", /* breadth-first search */ + " #ifndef BFS_PAR", + " BFS_State *bfs_trail, *bfs_bot, *bfs_free;", + " SV_Hold *svfree;", + " #else", + " static ulong bfs_pre_allocated;", + " #endif", + " #ifdef BFS_DISK", + " #ifndef BFS_LIMIT", + " #define BFS_LIMIT 100000", + " #endif", + " #ifndef BFS_DSK_LIMIT", + " #define BFS_DSK_LIMIT 1000000", + " #endif", + " #if defined(WIN32) || defined(WIN64)", + " #define RFLAGS (O_RDONLY|O_BINARY)", + " #define WFLAGS (O_CREAT|O_WRONLY|O_TRUNC|O_BINARY)", + " #define RWFLAGS (O_RDWR|O_BINARY)", + " #else", + " #define RFLAGS (O_RDONLY)", + " #define WFLAGS (O_CREAT|O_WRONLY|O_TRUNC)", + " #define RWFLAGS (O_RDWR)", + " #endif", "", - "BFS_Trail *bfs_trail, *bfs_bot, *bfs_free;", - "", - "SV_Hold *svhold, *svfree;", + " long bfs_size_limit;", + " int bfs_dsk_write = -1;", + " int bfs_dsk_read = -1;", + " long bfs_dsk_writes, bfs_dsk_reads;", + " int bfs_dsk_seqno_w, bfs_dsk_seqno_r;", + " #endif", "", "uchar do_reverse(Trans *, short, uchar);", "void snapshot(void);", + "#if 0", + "void", + "select_claim(int x) /* ignored in BFS mode */", + "{ if (verbose)", + " { printf(\"select %%d (ignored)\\n\", x);", + " }", + "}", + "#endif", + "Trail *ntrpt;", "", + "#ifndef BFS_PAR", "SV_Hold *", "getsv(int n)", - "{ SV_Hold *h = (SV_Hold *) 0, *oh;", + "{ SV_Hold *h;", "", - " 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)", + " if (svfree && n <= svfree->sz)", + " { h = svfree;", + " svfree = h->nxt;", + " h->nxt = (SV_Hold *) 0;", + " } else", " { h = (SV_Hold *) emalloc(sizeof(SV_Hold));", " h->sz = n;", + " #ifdef BFS_DISK", + " if (bfs_size_limit >= BFS_LIMIT)", + " { h->sv = (State *) 0; /* means: read disk */", + " bfs_dsk_writes++; /* count */", + " if (bfs_dsk_write < 0 /* file descriptor */", + " || bfs_dsk_writes%%BFS_DSK_LIMIT == 0)", + " { char dsk_nm[32];", + " if (bfs_dsk_write >= 0)", + " { (void) close(bfs_dsk_write);", + " }", + " sprintf(dsk_nm, \"pan_bfs_%%d.tmp\", bfs_dsk_seqno_w++);", + " bfs_dsk_write = open(dsk_nm, WFLAGS, 0644);", + " if (bfs_dsk_write < 0)", + " { Uerror(\"could not create tmp disk file\");", + " }", + " printf(\"pan: created disk file %%s\\n\", dsk_nm);", + " }", + " if (write(bfs_dsk_write, (char *) &now, n) != n)", + " { Uerror(\"aborting -- disk write failed (disk full?)\");", + " }", + " return h; /* no memcpy */", + " }", /* else */ + " bfs_size_limit++;", + " #endif", " h->sv = (State *) emalloc(sizeof(State) - VECTORSZ + n);", " }", + "", + " memcpy((char *)h->sv, (char *)&now, n);", " return h;", "}", "", @@ -669,18 +1139,24 @@ static char *Code2b[] = { /* breadth-first search option */ "", " for (h = kept; h; h = h->nxt)", " if (n == h->sz", + "#if !defined(NOCOMP) && !defined(HC)", " && (memcmp((char *) Mask, (char *) h->sv, n) == 0)", + "#endif", " && (now._nr_pr == h->nrpr)", " && (now._nr_qs == h->nrqs)", - "#if VECTORSZ>32000", + " #ifdef TRIX", + " )", + " #else", + " #if VECTORSZ>32000", " && (memcmp((char *) proc_offset, (char *) h->po, now._nr_pr * sizeof(int)) == 0)", " && (memcmp((char *) q_offset, (char *) h->qo, now._nr_qs * sizeof(int)) == 0)", - "#else", + " #else", " && (memcmp((char *) proc_offset, (char *) h->po, now._nr_pr * sizeof(short)) == 0)", " && (memcmp((char *) q_offset, (char *) h->qo, now._nr_qs * sizeof(short)) == 0)", - "#endif", - " && (memcmp((char *) proc_skip, (char *) h->ps, now._nr_pr * sizeof(uchar)) == 0)", - " && (memcmp((char *) q_skip, (char *) h->qs, now._nr_qs * sizeof(uchar)) == 0))", + " #endif", + " && (memcmp((char *) proc_skip, (char *) h->ps, now._nr_pr * sizeof(uchar)) == 0)", + " && (memcmp((char *) q_skip, (char *) h->qs, now._nr_qs * sizeof(uchar)) == 0))", + " #endif", " break;", " if (!h)", " { h = (EV_Hold *) emalloc(sizeof(EV_Hold));", @@ -689,29 +1165,33 @@ static char *Code2b[] = { /* breadth-first search option */ " h->nrqs = now._nr_qs;", "", " h->sv = (char *) emalloc(n * sizeof(char));", + "#if !defined(NOCOMP) && !defined(HC)", " 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));", - "#if VECTORSZ>32000", - " memcpy((char *) h->po, (char *) proc_offset, now._nr_pr * sizeof(int));", - "#else", - " memcpy((char *) h->po, (char *) proc_offset, now._nr_pr * sizeof(short));", "#endif", + " #ifndef TRIX", + " if (now._nr_pr > 0)", + " { h->ps = (char *) emalloc(now._nr_pr * sizeof(int));", " memcpy((char *) h->ps, (char *) proc_skip, now._nr_pr * sizeof(uchar));", + " #if VECTORSZ>32000", + " h->po = (char *) emalloc(now._nr_pr * sizeof(int));", + " memcpy((char *) h->po, (char *) proc_offset, now._nr_pr * sizeof(int));", + " #else", + " h->po = (char *) emalloc(now._nr_pr * sizeof(short));", + " memcpy((char *) h->po, (char *) proc_offset, now._nr_pr * sizeof(short));", + " #endif", " }", " if (now._nr_qs > 0)", - " { h->qo = (int *) emalloc(now._nr_qs * sizeof(int));", - " h->qs = (int *) emalloc(now._nr_qs * sizeof(int));", - "#if VECTORSZ>32000", - " memcpy((char *) h->qo, (char *) q_offset, now._nr_qs * sizeof(int));", - "#else", - " memcpy((char *) h->qo, (char *) q_offset, now._nr_qs * sizeof(short));", - "#endif", + " { h->qs = (char *) emalloc(now._nr_qs * sizeof(int));", " memcpy((char *) h->qs, (char *) q_skip, now._nr_qs * sizeof(uchar));", + " #if VECTORSZ>32000", + " h->qo = (char *) emalloc(now._nr_qs * sizeof(int));", + " memcpy((char *) h->qo, (char *) q_offset, now._nr_qs * sizeof(int));", + " #else", + " h->qo = (char *) emalloc(now._nr_qs * sizeof(short));", + " memcpy((char *) h->qo, (char *) q_offset, now._nr_qs * sizeof(short));", + " #endif", " }", - "", + " #endif", " h->nxt = kept;", " kept = h;", " }", @@ -724,9 +1204,9 @@ static char *Code2b[] = { /* breadth-first search option */ "", " oh = (SV_Hold *) 0;", " for (h = svfree; h; oh = h, h = h->nxt)", - " if (h->sz >= p->sz)", + " { if (p->sz >= h->sz)", " break;", - "", + " }", " if (!oh)", " { p->nxt = svfree;", " svfree = p;", @@ -736,171 +1216,239 @@ static char *Code2b[] = { /* breadth-first search option */ " }", "}", "", - "BFS_Trail *", + "BFS_State *", "get_bfs_frame(void)", - "{ BFS_Trail *t;", + "{ BFS_State *t;", "", " if (bfs_free)", " { t = bfs_free;", " bfs_free = bfs_free->nxt;", - " t->nxt = (BFS_Trail *) 0;", + " t->nxt = (BFS_State *) 0;", " } else", - " { t = (BFS_Trail *) emalloc(sizeof(BFS_Trail));", + " { t = (BFS_State *) emalloc(sizeof(BFS_State));", " }", " t->frame = (Trail *) emalloc(sizeof(Trail));", /* always new */ + " /* new because we keep a ptr to the frame of parent states */", + " /* used for reconstructing path and recovering failed rvs etc */", " return t;", "}", "", "void", "push_bfs(Trail *f, int d)", - "{ BFS_Trail *t;", + "{ BFS_State *t;", "", " t = get_bfs_frame();", " memcpy((char *)t->frame, (char *)f, sizeof(Trail));", " t->frame->o_tt = d; /* depth */", "", " t->boq = boq;", + " #ifdef TRIX", + " sv_populate();", + " #endif", " t->onow = getsv(vsize);", - " memcpy((char *)t->onow->sv, (char *)&now, vsize);", " t->omask = getsv_mask(vsize);", - "#if defined(FULLSTACK) && defined(Q_PROVISO)", - " t->lstate = Lstate;", - "#endif", + " #if defined(FULLSTACK) && defined(Q_PROVISO)", + " t->lstate = Lstate; /* bfs */", + " #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", + " #ifdef VERBOSE", + " t->nr = nstates;", + " #endif", + " #ifdef CHECK", + " #ifdef VERBOSE", + " printf(\"PUSH %%lu (depth %%d, nr %%lu)\\n\", (ulong) t->frame, d, t->nr);", + " #else", + " printf(\"PUSH %%lu (depth %%d)\\n\", (ulong) t->frame, d);", + " #endif", + " #endif", "}", "", "Trail *", "pop_bfs(void)", - "{ BFS_Trail *t;", + "{ BFS_State *t;", "", " if (!bfs_trail)", - " return (Trail *) 0;", - "", + " { return (Trail *) 0;", + " }", " t = bfs_trail;", " bfs_trail = t->nxt;", " if (!bfs_trail)", - " bfs_bot = (BFS_Trail *) 0;", - "#if defined(Q_PROVISO) && !defined(BITSTATE) && !defined(NOREDUCE)", - " if (t->lstate) t->lstate->tagged = 0;", - "#endif", - "", + " { bfs_bot = (BFS_State *) 0;", + " }", + " #if defined(Q_PROVISO) && !defined(BITSTATE) && !defined(NOREDUCE)", + " if (t->lstate) /* bfs */", + " { t->lstate->tagged = 0; /* bfs */", + " }", + " #endif", " t->nxt = bfs_free;", " bfs_free = t;", "", " vsize = t->onow->sz;", " boq = t->boq;", - "", - " memcpy((uchar *) &now, (uchar *) t->onow->sv, vsize);", + " #ifdef BFS_DISK", + " if (t->onow->sv == (State *) 0)", + " { char dsk_nm[32];", + " bfs_dsk_reads++; /* count */", + " if (bfs_dsk_read >= 0 /* file descriptor */", + " && bfs_dsk_reads%%BFS_DSK_LIMIT == 0)", + " { (void) close(bfs_dsk_read);", + " sprintf(dsk_nm, \"pan_bfs_%%d.tmp\", bfs_dsk_seqno_r-1);", + " (void) unlink(dsk_nm);", + " bfs_dsk_read = -1;", + " }", + " if (bfs_dsk_read < 0)", + " { sprintf(dsk_nm, \"pan_bfs_%%d.tmp\", bfs_dsk_seqno_r++);", + " bfs_dsk_read = open(dsk_nm, RFLAGS);", + " if (bfs_dsk_read < 0)", + " { Uerror(\"could not open temp disk file\");", + " } }", + " if (read(bfs_dsk_read, (char *) &now, vsize) != vsize)", + " { Uerror(\"bad bfs disk file read\");", + " }", + " #ifndef NOVSZ", + " if (now._vsz != vsize)", + " { Uerror(\"disk read vsz mismatch\");", + " }", + " #endif", + " } else", + " #endif", + " { memcpy((uchar *) &now, (uchar *) t->onow->sv, vsize);", + " #ifndef NOVSZ", + " vsize = now._vsz;", + " #endif", + " }", + "#if !defined(NOCOMP) && !defined(HC)", " memcpy((uchar *) Mask, (uchar *) t->omask->sv, vsize);", - - " if (now._nr_pr > 0)", - "#if VECTORSZ>32000", - " { memcpy((char *)proc_offset, (char *)t->omask->po, now._nr_pr * sizeof(int));", - "#else", - " { memcpy((char *)proc_offset, (char *)t->omask->po, now._nr_pr * sizeof(short));", "#endif", + " #ifdef TRIX", + " re_populate();", + " #else", + " if (now._nr_pr > 0)", + " #if VECTORSZ>32000", + " { memcpy((char *)proc_offset, (char *)t->omask->po, now._nr_pr * sizeof(int));", + " #else", + " { memcpy((char *)proc_offset, (char *)t->omask->po, now._nr_pr * sizeof(short));", + " #endif", " memcpy((char *)proc_skip, (char *)t->omask->ps, now._nr_pr * sizeof(uchar));", " }", " if (now._nr_qs > 0)", - "#if VECTORSZ>32000", + " #if VECTORSZ>32000", " { memcpy((uchar *)q_offset, (uchar *)t->omask->qo, now._nr_qs * sizeof(int));", - "#else", + " #else", " { memcpy((uchar *)q_offset, (uchar *)t->omask->qo, now._nr_qs * sizeof(short));", - "#endif", + " #endif", " memcpy((uchar *)q_skip, (uchar *)t->omask->qs, now._nr_qs * sizeof(uchar));", " }", - - " freesv(t->onow); /* omask not freed */", - "#ifdef CHECK", - " printf(\"POP %%u (%%d)\\n\", t->frame, t->frame->o_tt);", - "#endif", + " #endif", + " #ifdef BFS_DISK", + " if (t->onow->sv != (State *) 0)", + " #endif", + " { freesv(t->onow); /* omask not freed */", + " }", + " #ifdef CHECK", + " #ifdef VERBOSE", + " printf(\"POP %%lu (depth %%d, nr %%lu)\\n\", (ulong) t->frame, t->frame->o_tt, t->nr);", + " #else", + " printf(\"POP %%lu (depth %%d)\\n\", (ulong) t->frame, t->frame->o_tt);", + " #endif", + " #endif", " return t->frame;", "}", "", "void", "store_state(Trail *ntrpt, int shortcut, short oboq)", "{", - "#ifdef VERI", + " #ifdef VERI", " Trans *t2 = (Trans *) 0;", " uchar ot; int tt, E_state;", " uchar o_opm = trpt->o_pm, *othis = this;", "", " if (shortcut)", " {", - "#ifdef VERBOSE", + " #ifdef VERBOSE", " printf(\"claim: shortcut\\n\");", - "#endif", + " #endif", " goto store_it; /* no claim move */", " }", "", - " this = (((uchar *)&now)+proc_offset[0]); /* 0 = never claim */", + " this = pptr(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", + " #ifdef HAS_UNLESS", " E_state = 0;", - "#endif", + " #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", + " #ifdef HAS_UNLESS", + " if (E_state > 0 && E_state != t2->e_trans)", + " { break;", + " }", + " #endif", " if (do_transit(t2, 0))", " {", - "#ifdef VERBOSE", + " #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", + " #endif", + " #ifdef HAS_UNLESS", " E_state = t2->e_trans;", - "#endif", + " #endif", " if (t2->st > 0)", " { ((P0 *)this)->_p = t2->st;", " reached[ot][t2->st] = 1;", - "#ifndef NOCLAIM", - " check_claim(t2->st);", - "#endif", + " #ifndef NOCLAIM", + " if (stopstate[ot][t2->st])", + " { uerror(\"end state in claim reached\");", + " }", + " #endif", " }", " if (now._nr_pr == 0) /* claim terminated */", " uerror(\"end state in claim reached\");", "", - "#ifdef PEG", + " #ifdef PEG", " peg[t2->forw]++;", - "#endif", + " #endif", " trpt->o_pm |= 1;", - " if (t2->atom&2)", /* atomic in claim */ - " Uerror(\"atomic in claim not supported in BFS mode\");", + " if (t2->atom&2)", + " { Uerror(\"atomic in claim not supported in BFS\");", + " }", "store_it:", "", - "#endif", /* VERI */ + " #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 defined(BITSTATE)", + " if (!b_store((char *)&now, vsize))", + " #elif defined(MA)", + " if (!g_store((char *)&now, vsize, 0))", + " #else", + " if (!h_store((char *)&now, vsize))", + " #endif", + " { static long sdone = (long) 0; long ndone;", + " nstates++;", + " #ifndef NOREDUCE", + " trpt->tau |= 64;", /* bfs: succ definitely outside stack */ + " #endif", + " ndone = (ulong) (nstates/(freq));", + " if (ndone != sdone && mreached%%10 != 0)", + " { snapshot();", + " sdone = ndone;", + " #if defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(MA)", + " if (nstates > ((double)(1<<(ssize+1))))", + " { void resize_hashtable(void);", + " resize_hashtable();", + " }", + " #endif", + " }", + " #if SYNC", " if (boq != -1)", " midrv++;", " else if (oboq != -1)", @@ -908,26 +1456,29 @@ static char *Code2b[] = { /* breadth-first search option */ " x = (Trail *) trpt->ostate; /* pre-rv state */", " if (x) x->o_pm |= 4; /* mark success */", " }", - "#endif", + " #endif", " push_bfs(ntrpt, trpt->o_tt+1);", " } else", " { truncs++;", - "#if !defined(NOREDUCE) && defined(FULLSTACK) && defined(Q_PROVISO)", - "#if !defined(QLIST) && !defined(BITSTATE)", - " if (Lstate && Lstate->tagged) trpt->tau |= 64;", - "#else", + " #if defined(Q_PROVISO) && !defined(NOREDUCE) && defined(FULLSTACK)", + " #if !defined(BITSTATE)", + " if (Lstate && Lstate->tagged)", + " { trpt->tau |= 64;", + " }", + " #else", " if (trpt->tau&32)", - " { BFS_Trail *tprov;", + " { BFS_State *tprov;", " for (tprov = bfs_trail; tprov; tprov = tprov->nxt)", - " if (!memcmp((uchar *)&now, (uchar *)tprov->onow->sv, vsize))", + " if (tprov->onow->sv != (State *) 0", + " && memcmp((uchar *)&now, (uchar *)tprov->onow->sv, vsize) == 0)", " { trpt->tau |= 64;", " break; /* state is in queue */", " } }", - "#endif", - "#endif", + " #endif", + " #endif", " }", - "#ifdef VERI", + " #ifdef VERI", " ((P0 *)this)->_p = tt; /* reset claim */", " if (t2)", " do_reverse(t2, 0, 0);", @@ -936,11 +1487,9 @@ static char *Code2b[] = { /* breadth-first search option */ " } }", " this = othis;", " trpt->o_pm = o_opm;", - "#endif", + " #endif", "}", "", - "Trail *ntrpt;", /* 4.2.8 */ - "", "void", "bfs(void)", "{ Trans *t; Trail *otrpt, *x;", @@ -950,7 +1499,7 @@ static char *Code2b[] = { /* breadth-first search option */ " short oboq = boq;", "", " ntrpt = (Trail *) emalloc(sizeof(Trail));", - " trpt->ostate = (struct H_el *) 0;", + " trpt->ostate = (H_el *) 0;", " trpt->tau = 0;", "", " trpt->o_tt = -1;", @@ -958,81 +1507,74 @@ static char *Code2b[] = { /* breadth-first search option */ "", " while ((otrpt = pop_bfs())) /* also restores now */", " { memcpy((char *) trpt, (char *) otrpt, sizeof(Trail));", - "#if defined(C_States) && (HAS_TRACK==1)", + " #if defined(C_States) && (HAS_TRACK==1)", " c_revert((uchar *) &(now.c_state[0]));", - "#endif", + " #endif", " if (trpt->o_pm & 4)", " {", - "#ifdef VERBOSE", + " #ifdef VERBOSE", " printf(\"Revisit of atomic not needed (%%d)\\n\",", " trpt->o_pm);", /* at least 1 rv succeeded */ - "#endif", + " #endif", " continue;", " }", - "#ifndef NOREDUCE", + " #ifndef NOREDUCE", " nps = 0;", - "#endif", + " #endif", " if (trpt->o_pm == 8)", " { revrv++;", " if (trpt->tau&8)", " {", - "#ifdef VERBOSE", + " #ifdef VERBOSE", " printf(\"Break atomic (pm:%%d,tau:%%d)\\n\",", " trpt->o_pm, trpt->tau);", - "#endif", + " #endif", " trpt->tau &= ~8;", " }", - "#ifndef NOREDUCE", + " #ifndef NOREDUCE", " else if (trpt->tau&32)", /* was a preselected move */ " {", - "#ifdef VERBOSE", + " #ifdef VERBOSE", " printf(\"Void preselection (pm:%%d,tau:%%d)\\n\",", " trpt->o_pm, trpt->tau);", - "#endif", + " #endif", " trpt->tau &= ~32;", " nps = 1; /* no preselection in repeat */", " }", - "#endif", + " #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);", + " { snapshot();", " } }", " depth = trpt->o_tt;", " if (depth >= maxdepth)", " {", - "#if SYNC", + " #if SYNC", " Trail *x;", " if (boq != -1)", " { x = (Trail *) trpt->ostate;", " if (x) x->o_pm |= 4; /* not failing */", " }", - "#endif", + " #endif", " truncs++;", " if (!warned)", " { warned = 1;", " printf(\"error: max search depth too small\\n\");", " }", " if (bounded)", - " uerror(\"depth limit reached\");", + " { uerror(\"depth limit reached\");", + " }", " continue;", " }", - -/* PO */ - "#ifndef NOREDUCE", + " #ifndef NOREDUCE", " if (boq == -1 && !(trpt->tau&8) && nps == 0)", " for (II = now._nr_pr-1; II >= BASE; II -= 1)", " {", - "Pickup: this = pptr(II);", + "Pickup: this = pptr(II);", " tt = (int) ((P0 *)this)->_p;", " ot = (uchar) ((P0 *)this)->_t;", " if (trans[ot][tt]->atom & 8)", /* safe */ @@ -1045,15 +1587,14 @@ static char *Code2b[] = { /* breadth-first search option */ " }", " From = To = II;", " trpt->tau |= 32; /* preselect marker */", - "#ifdef DEBUG", - " printf(\"%%3d: proc %%d PreSelected (tau=%%d)\\n\", ", + " #ifdef DEBUG", + " printf(\"%%3ld: proc %%d PreSelected (tau=%%d)\\n\", ", " depth, II, trpt->tau);", - "#endif", + " #endif", " goto MainLoop;", " } }", " trpt->tau &= ~32;", /* not preselected */ - "#endif", -/* PO */ + " #endif", /* if !NOREDUCE */ "Repeat:", " if (trpt->tau&8) /* atomic */", " { From = To = (short ) trpt->pr;", @@ -1066,32 +1607,44 @@ static char *Code2b[] = { /* breadth-first search option */ " _n = _m = 0;", " for (II = From; II >= To; II -= 1)", " {", - " this = (((uchar *)&now)+proc_offset[II]);", + " this = pptr(II);", " tt = (int) ((P0 *)this)->_p;", " ot = (uchar) ((P0 *)this)->_t;", - "#if SYNC", + " #if SYNC", " /* no rendezvous with same proc */", - " if (boq != -1 && trpt->pr == II) continue;", - "#endif", + " 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_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", + " #endif", + + " #ifdef HAS_PRIORITY", + " if (!highest_priority(((P0 *)this)->_pid, II, t))", + " { continue;", + " }", + " #else", + " #ifdef HAS_PROVIDED", + " if (!provided(II, ot, tt, t))", + " { continue;", + " }", + " #endif", + " #endif", + + " #ifdef HAS_UNLESS", " E_state = 0;", - "#endif", + " #endif", " for (t = trans[ot][tt]; t; t = t->nxt)", " {", - "#ifdef HAS_UNLESS", + " #ifdef HAS_UNLESS", " if (E_state > 0", " && E_state != t->e_trans)", " break;", - "#endif", + " #endif", " ntrpt->o_t = t;", "", " oboq = boq;", @@ -1101,136 +1654,147 @@ static char *Code2b[] = { /* breadth-first search option */ "", " trpt->o_pm |= 1; /* we moved */", " (trpt+1)->o_m = _m; /* for unsend */", - "#ifdef PEG", + " #ifdef PEG", " peg[t->forw]++;", - "#endif", - "#ifdef CHECK", - " printf(\"%%3d: proc %%d exec %%d, \",", + " #endif", + " #ifdef CHECK", + " printf(\"%%3ld: 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", + " #ifdef HAS_UNLESS", " if (t->e_trans)", " printf(\" (escapes to state %%d)\", t->st);", - "#endif", + " #endif", " printf(\" %%saccepting [tau=%%d]\\n\",", " (trpt->o_pm&2)?\"\":\"non-\", trpt->tau);", - "#endif", - "#ifdef HAS_UNLESS", + " #endif", + " #ifdef HAS_UNLESS", " E_state = t->e_trans;", - "#if SYNC>0", + " #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, \"error:\ta 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;", + " #endif", + " #endif", + " if (t->st > 0)", + " { ((P0 *)this)->_p = t->st;", + " }", "", - " /* ptr to pred: */ ntrpt->ostate = (struct H_el *) otrpt;", + " /* ptr to pred: */ ntrpt->ostate = (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", + " #ifdef EVENT_TRACE", " now._event = trpt->o_event;", - "#endif", - "", + " #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);", + " #ifdef CHECK", + " enter_critical(GLOBAL_LOCK); /* verbose mode */", + " #if NCORE>1", + " printf(\"cpu%%d: \", core_id);", + " #endif", + " printf(\"%%3lu: proc %%d \", depth, II);", " printf(\"reverses %%d, %%d to %%d,\",", " t->forw, tt, t->st);", - " printf(\" %%s [abit=%%d,adepth=%%d,\",", + " printf(\" %%s [abit=%%d,adepth=%%ld,\",", " t->tp, now._a_t, A_depth);", " printf(\"tau=%%d,%%d]\\n\",", " trpt->tau, (trpt-1)->tau);", - "#endif", + " leave_critical(GLOBAL_LOCK);", + " #endif", " reached[ot][t->st] = 1;", - " reached[ot][tt] = 1;", + " reached[ot][tt] = 1;", "", " ((P0 *)this)->_p = tt;", " _n |= _m;", " } }", -/* PO */ - "#ifndef NOREDUCE", + " #ifndef NOREDUCE", /* with PO */ " /* 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\", ", + " #ifdef DEBUG", + " cpu_printf(\"%%3ld: proc %%d UnSelected (_n=%%d, tau=%%d)\\n\", ", " depth, II+1, (int) _n, trpt->tau);", - "#endif", + " #endif", " _n = 0; trpt->tau &= ~32;", " if (II >= BASE)", - " goto Pickup;", + " { goto Pickup;", + " }", " goto MainLoop;", " }", " trpt->tau &= ~(32|64);", - "#endif", -/* PO */ + " #endif", /* PO */ " if (_n != 0)", - " continue;", - "#ifdef DEBUG", - " printf(\"%%3d: no move [II=%%d, tau=%%d, boq=%%d, _nr_pr=%%d]\\n\",", + " { continue;", + " }", + " #ifdef DEBUG", + " printf(\"%%3ld: no move [II=%%d, tau=%%d, boq=%%d, _nr_pr=%%d]\\n\",", " depth, II, trpt->tau, boq, now._nr_pr);", - "#endif", + " #endif", " if (boq != -1)", " { failedrv++;", - " x = (Trail *) trpt->ostate; /* pre-rv state */", - " if (!x) continue; /* root state */", + " 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", + " this = pptr(otrpt->pr);", + " #ifdef VERBOSE", " printf(\"\\treset state of %%d from %%d to %%d\\n\",", " otrpt->pr, ((P0 *)this)->_p, otrpt->st);", - "#endif", + " #endif", " ((P0 *)this)->_p = otrpt->st;", " unsend(boq); /* retract rv offer */", " boq = -1;", " push_bfs(x, x->o_tt);", - "#ifdef VERBOSE", + " #ifdef VERBOSE", " printf(\"failed rv, repush with %%d\\n\", x->o_pm);", - "#endif", + " #endif", " }", - "#ifdef VERBOSE", - " else printf(\"failed rv, tau at parent: %%d\\n\", x->tau);", - "#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\",", + " #ifdef DEBUG", + " printf(\"%%3ld: atomic step proc %%d blocks\\n\",", " depth, II+1);", - "#endif", + " #endif", " goto Repeat;", " }", "", " if (!(trpt->tau&1)) /* didn't try timeout yet */", " { trpt->tau |= 1;", - "#ifdef DEBUG", - " printf(\"%%d: timeout\\n\", depth);", - "#endif", + " #ifdef DEBUG", + " printf(\"%%ld: timeout\\n\", depth);", + " #endif", " goto MainLoop;", " }", - "#ifndef VERI", + " #ifndef VERI", " if (!noends && !a_cycles && !endstate())", - " uerror(\"invalid end state\");", - "#endif", + " { uerror(\"invalid end state\");", + " }", + " #endif", " } }", "}", + "#endif", /* !BFS_PAR */ "", "void", "putter(Trail *trpt, int fd)", @@ -1252,40 +1816,178 @@ static char *Code2b[] = { /* breadth-first search option */ "}", "", "void", - "nuerror(char *str)", + "n_ewrite(int fd, char *s, int n)", + "{ if (write(fd, s, strlen(s)) != strlen(s))", + " { printf(\"pan: error writing %%s\\n\", fnm);", + " pan_exit(1);", + " }", + "}", + "", + "void", + "nuerror(void)", "{ int fd = make_trail();", " int j;", "", " 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", + " #ifdef VERI", + " sprintf(snap, \"-2:%%d:-2\\n\", (uchar) ((P0 *)pptr(0))->_t);", + " n_ewrite(fd, snap, strlen(snap));", + " #endif", + " #ifdef MERGED", + " sprintf(snap, \"-4:-4:-4\\n\");", + " n_ewrite(fd, snap, strlen(snap));", + " #endif", " trcnt = 1;", " putter(trpt, fd);", " if (ntrpt->o_t)", /* 4.2.8 -- Alex example, missing last transition */ " { sprintf(snap, \"%%d:%%d:%%d\\n\",", " trcnt++, ntrpt->pr, ntrpt->o_t->t_id);", " j = strlen(snap);", - " if (write(fd, snap, j) != j)", - " { printf(\"pan: error writing %%s\\n\", fnm);", - " pan_exit(1);", - " } }", + " n_ewrite(fd, snap, j);", + " }", " close(fd);", " if (errors >= upto && upto != 0)", - " {", - " wrapup();", + " { wrapup();", " }", "}", "#endif", /* BFS */ 0, }; -static char *Code2c[] = { +static const char *Code2d[] = { + "clock_t start_time;", + "#if NCORE>1", + "clock_t crash_stamp;", + "#endif", + "#if !defined(WIN32) && !defined(WIN64)", + "struct tms start_tm;", + "#endif", + "", + "#if SYNC", + "extern int q_zero(int);", + "extern int not_RV(int);", + "#endif", + "", + "void", + "start_timer(void)", + "{", + "#if defined(WIN32) || defined(WIN64)", + " start_time = clock();", + "#else", + " start_time = times(&start_tm);", + "#endif", + "}", + "", + "double delta_time;", + "", + "void", + "report_time(void)", + "{", + " printf(\"\\npan: elapsed time %%.3g seconds\\n\", delta_time);", + " if (delta_time > 0.01)", + " { printf(\"pan: rate %%9.8g states/second\\n\", nstates/delta_time);", + " if (verbose)", + " { printf(\"pan: avg transition delay %%.5g usec\\n\",", + " delta_time/(nstates+truncs));", + " } }", + "}", + "", + "void", + "stop_timer(int report)", + "{ clock_t stop_time;", + "#if !defined(WIN32) && !defined(WIN64)", + " struct tms stop_tm;", + " stop_time = times(&stop_tm);", + " delta_time = ((double) (stop_time - start_time)) / ((double) sysconf(_SC_CLK_TCK));", + "#else", + " stop_time = clock();", + " delta_time = ((double) (stop_time - start_time)) / ((double) CLOCKS_PER_SEC);", + "#endif", + " if (readtrail || delta_time < 0.00) return;", + "#if NCORE>1", + " if (core_id == 0 && nstates > (double) 0)", + " { printf(\"\\ncpu%%d: elapsed time %%.3g seconds (%%g states visited)\\n\",", + " core_id, delta_time, nstates);", + " if (delta_time > 0.01)", + " { printf(\"cpu%%d: rate %%g states/second\\n\", core_id, nstates/delta_time);", + " }", + " { void check_overkill(void);", + " check_overkill();", + " } }", + "#else", + " if (report)", + " { report_time();", + " }", + "#endif", + "}", + "", + "#if NCORE>1", + "#ifdef T_ALERT", + "double t_alerts[17];", + "", + "void", + "crash_report(void)", + "{ int i;", + " printf(\"crash alert intervals:\\n\");", + " for (i = 0; i < 17; i++)", + " { printf(\"%%d\\t%%g\\n\", i, t_alerts[i]);", + "} }", + "#endif", + "", + "void", + "crash_reset(void)", + "{ /* false alarm */", + " if (crash_stamp != (clock_t) 0)", + " {", + "#ifdef T_ALERT", + " double delta_time;", + " int i;", + "#if defined(WIN32) || defined(WIN64)", + " delta_time = ((double) (clock() - crash_stamp)) / ((double) CLOCKS_PER_SEC);", + "#else", + " delta_time = ((double) (times(&start_tm) - crash_stamp)) / ((double) sysconf(_SC_CLK_TCK));", + "#endif", + " for (i = 0; i < 16; i++)", + " { if (delta_time <= (i*30))", + " { t_alerts[i] = delta_time;", + " break;", + " } }", + " if (i == 16) t_alerts[i] = delta_time;", + "#endif", + " if (verbose)", + " printf(\"cpu%%d: crash alert off\\n\", core_id);", + " }", + " crash_stamp = (clock_t) 0;", + "}", + "", + "int", + "crash_test(double maxtime)", + "{ double delta_time;", + " if (crash_stamp == (clock_t) 0)", + " { /* start timing */", + "#if defined(WIN32) || defined(WIN64)", + " crash_stamp = clock();", + "#else", + " crash_stamp = times(&start_tm);", + "#endif", + " if (verbose)", + " { printf(\"cpu%%d: crash detection\\n\", core_id);", + " }", + " return 0;", + " }", + "#if defined(WIN32) || defined(WIN64)", + " delta_time = ((double) (clock() - crash_stamp)) / ((double) CLOCKS_PER_SEC);", + "#else", + " delta_time = ((double) (times(&start_tm) - crash_stamp)) / ((double) sysconf(_SC_CLK_TCK));", + "#endif", + " return (delta_time >= maxtime);", + "}", + "#endif", + "", + "#ifdef BFS_PAR", + "int ncores = 0;", + "#endif", + "", "void", "do_the_search(void)", "{ int i;", @@ -1300,11 +2002,13 @@ static char *Code2c[] = { " if (!(trpt->o_pm&2)", " && accpstate[ptr->_t][ptr->_p])", " { trpt->o_pm |= 2;", + " break;", " }", "#else", " if (!(trpt->o_pm&4)", " && progstate[ptr->_t][ptr->_p])", " { trpt->o_pm |= 4;", + " break;", " }", "#endif", " }", @@ -1319,20 +2023,20 @@ static char *Code2c[] = { " }", "#endif", "#endif", - "#ifndef NOCOMP", + "#if !defined(NOCOMP) && !defined(HC)", " Mask[0] = Mask[1] = 1; /* _nr_pr, _nr_qs */", " if (!a_cycles)", " { i = &(now._a_t) - (uchar *) &now;", " Mask[i] = 1; /* _a_t */", " }", - "#ifndef NOFAIR", - " if (!fairness)", - " { int j = 0;", - " i = &(now._cnt[0]) - (uchar *) &now;", - " while (j++ < NFAIR)", - " Mask[i++] = 1; /* _cnt[] */", - " }", - "#endif", + " #ifndef NOFAIR", + " if (!fairness)", + " { int j = 0;", + " i = &(now._cnt[0]) - (uchar *) &now;", + " while (j++ < NFAIR)", + " Mask[i++] = 1; /* _cnt[] */", + " }", + " #endif", "#endif", "#ifndef NOFAIR", " if (fairness", @@ -1340,12 +2044,19 @@ static char *Code2c[] = { " { now._a_t = 2; /* set the A-bit */", " now._cnt[0] = now._nr_pr + 1;", /* NEW: +1 */ "#ifdef VERBOSE", - " printf(\"%%3d: fairness Rule 1, cnt=%%d, _a_t=%%d\\n\",", + " printf(\"%%3ld: fairness Rule 1, cnt=%%d, _a_t=%%d\\n\",", " depth, now._cnt[now._a_t&1], now._a_t);", "#endif", " }", "#endif", + " c_stack_start = (char *) &i; /* meant to be read-only */", + + "#if defined(HAS_CODE) && defined (C_INIT)", + " C_INIT; /* initialization of data that must precede fork() */", + " c_init_done++;", + "#endif", + "#if defined(C_States) && (HAS_TRACK==1)", " /* capture initial state of tracked C objects */", " c_update((uchar *) &(now.c_state[0]));", @@ -1354,17 +2065,30 @@ static char *Code2c[] = { "#ifdef HAS_CODE", " if (readtrail) getrail(); /* no return */", "#endif", + "#ifndef BFS_PAR", + " start_timer();", + "#endif", "#ifdef BFS", - " bfs();", + " #ifdef BFS_PAR", + " bfs_main(ncores,0);", + " #else", + " bfs();", + " #endif", "#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 */", + " #if defined(C_States) && defined(HAS_STACK) && (HAS_TRACK==1)", + " /* initial state of tracked & unmatched objects */", + " c_stack((uchar *) &(svtack->c_stack[0]));", + " #endif", + + " #if defined(P_RAND) || defined(T_RAND)", + " srand(s_rand+HASH_NR);", /* do_the_search */ + " #endif", + + " #if NCORE>1", + " mem_get();", + " #else", + " new_state(); /* start 1st DFS */", + " #endif", "#endif", "}", @@ -1373,42 +2097,41 @@ static char *Code2c[] = { "do_reverse(Trans *t, short II, uchar M)", "{ uchar _m = M;", " int tt = (int) ((P0 *)this)->_p;", - "#include REVERSE_MOVES", + "#include BACKWARD_MOVES", "R999: return _m;", "}", "#endif", "#ifndef INLINE", - "#ifdef EVENT_TRACE", + " #ifdef EVENT_TRACE", "static char _tp = 'n'; static int _qid = 0;", - "#endif", + " #endif", "uchar", "do_transit(Trans *t, short II)", "{ uchar _m = 0;", " int tt = (int) ((P0 *)this)->_p;", - "#ifdef M_LOSS", + " #ifdef M_LOSS", " uchar delta_m = 0;", - "#endif", - "#ifdef EVENT_TRACE", + " #endif", + " #ifdef EVENT_TRACE", " short oboq = boq;", " uchar ot = (uchar) ((P0 *)this)->_t;", - " if (ot == EVENT_TRACE) boq = -1;", + " if (II == -EVENT_TRACE) boq = -1;", "#define continue { boq = oboq; return 0; }", - "#else", + " #else", "#define continue return 0", "#ifdef SEPARATE", " uchar ot = (uchar) ((P0 *)this)->_t;", "#endif", - "#endif", + " #endif", "#include FORWARD_MOVES", "P999:", - "#ifdef EVENT_TRACE", - " if (ot == EVENT_TRACE) boq = oboq;", - "#endif", + " #ifdef EVENT_TRACE", + " if (II == -EVENT_TRACE) boq = oboq;", + " #endif", " return _m;", - "#undef continue", + " #undef continue", "}", - "#ifdef EVENT_TRACE", "void", "require(char tp, int qid)", @@ -1417,67 +2140,65 @@ static char *Code2c[] = { "", " if (now._event != endevent)", " for (t = trans[EVENT_TRACE][now._event]; t; t = t->nxt)", - " { if (do_transit(t, EVENT_TRACE))", + " { if (do_transit(t, -EVENT_TRACE))", " { now._event = t->st;", " reached[EVENT_TRACE][t->st] = 1;", - "#ifdef VERBOSE", + " #ifdef VERBOSE", " printf(\" event_trace move to -> %%d\\n\", t->st);", - "#endif", - "#ifndef BFS", - "#ifndef NP", + " #endif", + " #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", + " #endif", + " #endif", + " #ifdef NEGATED_TRACE", " if (now._event == endevent)", " {", - "#ifndef BFS", + " #ifndef BFS", " depth++; trpt++;", - "#endif", + " #endif", " uerror(\"event_trace error (all events matched)\");", - "#ifndef BFS", + " #ifndef BFS", " trpt--; depth--;", - "#endif", + " #endif", " break;", " }", - "#endif", + " #endif", " for (t = t->nxt; t; t = t->nxt)", - " { if (do_transit(t, EVENT_TRACE))", + " { if (do_transit(t, -EVENT_TRACE))", " Uerror(\"non-determinism in event-trace\");", " }", " return;", " }", - "#ifdef VERBOSE", + " #ifdef VERBOSE", " else", " printf(\" event_trace miss '%%c' -- %%d, %%d, %%d\\n\",", " tp, qid, now._event, t->forw);", - "#endif", + " #endif", " }", - "#ifdef NEGATED_TRACE", + " #ifdef NEGATED_TRACE", " now._event = endevent; /* only 1st try will count -- fixed 4.2.6 */", - "#else", - "#ifndef BFS", + " #else", + " #ifndef BFS", " depth++; trpt++;", - "#endif", + " #endif", " uerror(\"event_trace error (no matching event)\");", - "#ifndef BFS", + " #ifndef BFS", " trpt--; depth--;", - "#endif", - "#endif", + " #endif", + " #endif", "}", "#endif", - "int", "enabled(int iam, int pid)", "{ Trans *t; uchar *othis = this;", " int res = 0; int tt; uchar ot;", - "#ifdef VERI", - " /* if (pid > 0) */ pid++;", - "#endif", + "", + " pid += BASE;", " if (pid == iam)", " Uerror(\"used: enabled(pid=thisproc)\");", " if (pid < 0 || pid >= (int) now._nr_pr)", @@ -1496,21 +2217,132 @@ static char *Code2c[] = { " return res;", "}", "#endif", + "", + "#ifdef HAS_PRIORITY", + "int", + "highest_priority(int pid, short nII, Trans *t)", + "{ int i = pid; uchar *othis = this;", + "", + "#ifdef VERI", + " if (nII == 0)", + " { return 1;", /* never claim */ + " }", + "#endif", + "#ifdef HAS_PROVIDED", + " i = pid+BASE;", /* uncorrected process number */ + "#endif", + " if (i < 0", + " || i >= (int) now._nr_pr", + "#ifdef HAS_PROVIDED", + " || !provided(i, (uchar) ((P0 *)this)->_t, (int) ((P0 *)this)->_p, t)", + "#endif", + " )", + " { return 0;", + " }", + "", + " for (i = BASE; i < now._nr_pr; i++)", /* all except never, if present */ + " { this = pptr(i);", + " if (i != pid+BASE", + " && ((P0 *)this)->_priority > ((P0 *)pptr(pid+BASE))->_priority", + "#ifdef HAS_PROVIDED", + " && provided(i, (uchar) ((P0 *)this)->_t, (int) ((P0 *)this)->_p, 0)", + "#endif", + " && enabled(i+1, i-BASE))", /* enabled adds back BASE in 2nd arg */ + " { this = othis;", + " return 0;", + " } }", + " this = othis;", + " return 1;", + "}", + "int", + "get_priority(int pid)", + "{ pid += BASE; /* 6.2.7 */", + " if (pid < 0 || pid >= (int) now._nr_pr)", + " return 0;", + " return ((P0 *)pptr(pid))->_priority;", + "}", + "int", + "set_priority(int pid, int pr)", + "{ pid += BASE; /* 6.2.7 */", + " if (pid < 0 || pid >= (int) now._nr_pr)", + " {", + " #ifdef VERBOSE", + " printf(\"warning: bad pid %%d, no such process (set_priority)\\n\", pid);", + " #endif", + " return 1;", + " }", + " if (pr < 1 || pr > 255)", + " { Uerror(\"priority is out of range\");", + " }", + + " if (!TstOnly)", + " { (trpt+1)->o_priority = ", + " (((P0 *)pptr(pid))->_priority & 255) | (pid << 8);", + " ((P0 *)pptr(pid))->_priority = pr;", + " }", + + " return 1;", /* always executable */ + "}", + "#endif", + "", + "void", + "snap_time(void)", + "{ clock_t stop_time;", + " double delta_time;", + "#if !defined(WIN32) && !defined(WIN64)", + " struct tms stop_tm;", + " stop_time = times(&stop_tm);", + " delta_time = ((double) (stop_time - start_time)) / ((double) sysconf(_SC_CLK_TCK));", + "#else", + " stop_time = clock();", + " delta_time = ((double) (stop_time - start_time)) / ((double) CLOCKS_PER_SEC);", + "#endif", + " if (delta_time > 0.01)", + " { printf(\"t= %%8.3g \", delta_time);", + " printf(\"R= %%7.0g\", nstates/delta_time);", + " }", + " printf(\"\\n\");", + " if (quota > 0.1 && delta_time > quota)", + " { printf(\"Time limit of %%6.3g minutes exceeded\\n\", quota/60.0);", + "#if NCORE>1", + " fflush(stdout);", + " leave_critical(GLOBAL_LOCK);", + " sudden_stop(\"time-limit\");", + " exit(1);", + "#endif", + " wrapup();", + " }", + "}", "void", "snapshot(void)", - "{ static long sdone = (long) 0;", - " long ndone = (unsigned long) nstates/1000000;", - " if (ndone == sdone) return;", - " sdone = ndone;", - " printf(\"Depth= %%7d States= %%7g \", mreached, nstates);", - " printf(\"Transitions= %%7g \", nstates+truncs);", - "#ifdef MA", - " printf(\"Nodes= %%7d \", nr_states);", + "{", + "#ifdef BFS_PAR", + " e_critical(BFS_GLOB); /* bfs_par / snapshot */", + " printf(\"cpu%%d: \", who_am_i);", "#endif", - " printf(\"Memory= %%-6.3f\\n\", memcnt/1000000.);", + "#if NCORE>1", + " enter_critical(GLOBAL_LOCK); /* ncore / snapshot */", + " printf(\"cpu%%d: \", core_id);", + "#endif", + " printf(\"Depth= %%7ld States= %%8.3g \",", + "#if NCORE>1", + " (long) (nr_handoffs * z_handoff) +", + "#endif", + " mreached, nstates);", + " printf(\"Transitions= %%8.3g \", nstates+truncs);", + "#ifdef MA", + " printf(\"Nodes= %%7lu \", nr_states);", + "#endif", + " printf(\"Memory= %%9.3f\\t\", memcnt/1048576.);", + " snap_time();", " fflush(stdout);", + "#if NCORE>1", + " leave_critical(GLOBAL_LOCK);", + "#endif", + "#ifdef BFS_PAR", + " x_critical(BFS_GLOB);", + "#endif", "}", - "#ifdef SC", "void", "stack2disk(void)", @@ -1552,46 +2384,246 @@ static char *Code2c[] = { "#endif", "uchar *", - "Pptr(int x)", /* as a fct, to avoid a problem with the p9 compiler */ - "{ if (x < 0 || x >= MAXPROC || !proc_offset[x])", /* does not exist */ + "Pptr(int x)", + "{ if (x < 0 || x >= MAXPROC", /* does not exist */ + "#ifdef TRIX", + " || !processes[x])", + "#else", + " || !proc_offset[x])", + "#endif", " return noptr;", " else", " return (uchar *) pptr(x);", + "}\n", + "uchar *", + "Qptr(int x)", + "{ if (x < 0 || x >= MAXQ", + "#ifdef TRIX", + " || !channels[x])", + "#else", + " || !q_offset[x])", + "#endif", + " return noqptr;", + " else", + " return (uchar *) qptr(x);", + "}\n", + "", + "#if NCLAIMS>1", + "void", + "select_claim(int n)", + "{ int m, i;", + " if (n < 0 || n >= NCLAIMS)", + " { uerror(\"non-existing claim\");", + " } else", + " { m = ((Pclaim *)pptr(0))->_n;", + " if (verbose)", + " { printf(\"%%d: Claim %%s (%%d), from state %%d\\n\",", + " (int) depth, procname[spin_c_typ[n]],", + " n, ((Pclaim *)pptr(0))->c_cur[n]);", + " } else", + " { printf(\"pan: ltl formula %%s\\n\",", + " procname[spin_c_typ[n]]);", + " }", + " ((Pclaim *)pptr(0))->c_cur[m] = ((Pclaim *)pptr(0))->_p;", + " ((Pclaim *)pptr(0))->_t = spin_c_typ[n];", + " ((Pclaim *)pptr(0))->_p = ((Pclaim *)pptr(0))->c_cur[n];", + " ((Pclaim *)pptr(0))->_n = n;", + " for (i = 0; src_all[i].src != (short *) 0; i++)", + " { if (src_all[i].tp == spin_c_typ[n])", + " { src_claim = src_all[i].src;", + " break;", + " } }", + " if (src_all[i].src == (short *) 0)", + " { uerror(\"cannot happen: src_ln ref\");", + " } }", "}", - "int qs_empty(void);", + "#else", + "void", + "select_claim(int n)", + "{ if (n != 0) uerror(\"non-existing claim\");", + "}", + "#endif", + "int qs_empty(void);", + "#if !defined(BFS) && (!defined(BITSTATE) || !defined(MA))", + "#ifdef NSUCC", + "int N_succ[512];", + "void", + "tally_succ(int cnt)", + "{ if (cnt < 512) N_succ[cnt]++;", + " else printf(\"tally_succ: cnt %%d exceeds range\\n\", cnt);", + "}", + "", + "void", + "dump_succ(void)", + "{ int i; double sum = 0.0;", + " double w_avg = 0.0;", + " printf(\"Successor counts:\\n\");", + " for (i = 0; i < 512; i++)", + " { sum += (double) N_succ[i];", + " }", + " for (i = 0; i < 512; i++)", + " { if (N_succ[i] > 0)", + " { printf(\"%%3d\t%%10d\t(%%.4g %%%% of total)\\n\",", + " i, N_succ[i], (100.0 * (double) N_succ[i])/sum);", + " w_avg += (double) i * (double) N_succ[i];", + " } }", + " if (sum > N_succ[0])", + " printf(\"mean %%.4g (without 0: %%.4g)\\n\", w_avg / sum, w_avg / (sum - (double) N_succ[0]));", + "}", + "#endif", + "", + "#ifdef P_REVERSE", + " #define FROM_P (BASE)", + " #define UPTO_P (now._nr_pr-1)", + " #define MORE_P (II <= To)", /* p.o. only */ + " #define INI_P (From-1)", /* fairness only */ + " #define CNT_P (1 + (To - From))", /* P_RAND start */ + " #define NDONE_P (From <= To)", /* P_RAND continue */ + " #define ALL_P (II = From; II <= To; II++)", + "#else", + " #define FROM_P (now._nr_pr-1)", + " #define UPTO_P (BASE)", + " #define MORE_P (II >= BASE)", + " #define INI_P (From+1)", + " #define CNT_P (1 + (From - To))", + " #define NDONE_P (From >= To)", + " #define ALL_P (II = From; II >= To; II--)", + "#endif", + "", + "#ifdef PERMUTED", + " #define CONTINUE0 { if (reversing&2) { II = oII; } continue; }", + " #define CONTINUE { if (reversing&2) { p_reorder(seed); II = oII; } continue; }", + "#else", + " #define CONTINUE0 { continue; }", + " #define CONTINUE { continue; }", + "#endif", + + "#ifdef PERMUTED", + "uchar _permutation_[256];", + "void", + "set_reversed(int unused)", + "{ int i, n = now._nr_pr;", + " #ifdef VERBOSE", + " printf(\"%%ld: Set_reversed\\n\", depth);", + " #endif", + " #if defined(VERI) && !defined(NOCLAIM)", + " for (i = 1; i < n; i++)", + " { _permutation_[i] = n-i;", + " }", + " #else", + " for (i = 0; i < n; i++)", + " { _permutation_[i] = n-1-i;", + " }", + " #endif", + "}", + "void", + "set_rotated(int unused)", + "{ int i, n = now._nr_pr;", + " #ifdef VERBOSE", + " printf(\"%%ld: Set_rotated %%d\\n\", depth, p_rotate);", + " #endif", + " #if defined(VERI) && !defined(NOCLAIM)", + " for (i = 1; i < n; i++)", + " { _permutation_[i] = 1+(i-1+p_rotate)%%(n-1);", + " }", + " #else", + " for (i = 0; i < n; i++)", + " { _permutation_[i] = (i+p_rotate)%%n;", + " }", + " #endif", + "}", + "void", + "set_randrot(int unused)", + "{", + " if (now._nr_pr > 1)", + " { p_rotate = 1+rand()%%(now._nr_pr-1);", + " } else", + " { p_rotate = 0;", + " }", + " set_rotated(0);", + "}", + "void", + "set_permuted(int T)", + "{ /* permute nrs 1..n-1, leave 0 in place */", + " int i, j, k, n = now._nr_pr;", + " char tmp, *in = &(_permutation_[0]);", + " #ifdef VERBOSE", + " printf(\"%%ld: Set_permuted %%d\\n\", depth, T);", + " #endif", + " srand(T);", /* set_permuted */ + " for (i = 0; i < n; i++)", + " { in[i] = i;", + " }", + " if (n > 1)", + " { for (i = 0; i < n; i++)", + " {", + " #if defined(VERI) && !defined(NOCLAIM)", + " j = 1 + rand()%%(n-1);", + " k = 1 + rand()%%(n-1);", + " #else", + " j = rand()%%(n);", + " k = rand()%%(n);", + " #endif", + " tmp = in[j];", + " in[j] = in[k];", + " in[k] = tmp;", + " } }", + "}", + "", + " #ifdef VERBOSE", + " short", + " get_permuted(int x)", + " { printf(\"%%ld: Get_permuted %%d -> %%d\\n\",", + " depth, x, _permutation_[x]);", + " return (short) _permutation_[x];", + " }", + " #else", + " #define get_permuted(x) (short) _permutation_[x]", + " #endif", + "", + "#endif", "/*", " * 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, which makes it quite unreadable.", - " * if you are studying the code, first use the C preprocessor", + " * if you are studying the code, 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", + " * and then study the resulting file, instead of this version", " */", - "#if !defined(BFS) && (!defined(BITSTATE) || !defined(MA))", + "", "void", "new_state(void)", "{ Trans *t;", " uchar _n, _m, ot;", - "#ifdef RANDOMIZE", + "#ifdef T_RAND", " short ooi, eoi;", "#endif", + "#ifdef PERMUTED", + " short oII; uint seed;", + "#endif", "#ifdef M_LOSS", " uchar delta_m = 0;", "#endif", " short II, JJ = 0, kk;", " int tt;", - " short From = now._nr_pr-1, To = BASE;", + " short From = FROM_P, To = UPTO_P;", + "#ifdef BCS", + " trpt->sched_limit = 0; /* at depth=0 only */", + "#endif", "Down:", "#ifdef CHECK", - " printf(\"%%d: Down - %%s\",", - " depth, (trpt->tau&4)?\"claim\":\"program\");", - " printf(\" %%saccepting [pids %%d-%%d]\\n\",", + " cpu_printf(\"%%d: Down - %%s %%saccepting [pids %%d-%%d]\\n\",", + " depth, (trpt->tau&4)?\"claim\":\"program\",", " (trpt->o_pm&2)?\"\":\"non-\", From, To);", "#endif", + "#ifdef P_RAND", + " trpt->p_skip = -1;", + "#endif", + "#ifdef SC", " if (depth > hiwater)", " { stack2disk();", @@ -1599,7 +2631,7 @@ static char *Code2c[] = { " hiwater += DDD;", " trpt -= DDD;", " if(verbose)", - " printf(\"zap %%d: %%d (maxdepth now %%d)\\n\",", + " printf(\"zap %%ld: %%ld (maxdepth now %%ld)\\n\",", " CNT1, hiwater, maxdepth);", " }", "#endif", @@ -1608,126 +2640,233 @@ static char *Code2c[] = { "#if defined(FULLSTACK) && defined(MA)", " trpt->proviso = 0;", "#endif", - " if (depth >= maxdepth)", - " { truncs++;", - "#if SYNC", - " (trpt+1)->o_n = 1; /* not a deadlock */", + "#ifdef NSUCC", + " trpt->n_succ = 0;", "#endif", - " if (!warned)", + "#if NCORE>1", + " if (mem_hand_off())", + " {", + "#if SYNC", + " (trpt+1)->o_n = 1; /* not a deadlock: as below */", + "#endif", + "#ifndef LOOPSTATE", + " (trpt-1)->tau |= 16; /* worstcase guess: as below */", + "#endif", + "#if NCORE>1 && defined(FULL_TRAIL)", + " if (upto > 0)", + " { Pop_Stack_Tree();", + " }", + "#endif", + " goto Up;", + " }", + "#endif", + + " if (depth >= maxdepth)", + " { if (!warned)", " { warned = 1;", " printf(\"error: max search depth too small\\n\");", " }", - " if (bounded) uerror(\"depth limit reached\");", - " (trpt-1)->tau |= 16; /* worstcase guess */", + " if (bounded)", + " { uerror(\"depth limit reached\");", + " }", + " truncs++;", + "#if SYNC", + " (trpt+1)->o_n = 1; /* not a deadlock */", + "#endif", + "#ifndef LOOPSTATE", + " (trpt-1)->tau |= 16; /* worstcase guess */", + "#endif", + + "#if NCORE>1 && defined(FULL_TRAIL)", + " if (upto > 0)", + " { Pop_Stack_Tree();", + " }", + "#endif", " goto Up;", " }", "AllOver:", - "#if defined(FULLSTACK) && !defined(MA)", + "#if (defined(FULLSTACK) && !defined(MA)) || NCORE>1", " /* if atomic or rv move, carry forward previous state */", - " trpt->ostate = (trpt-1)->ostate;", /* was: = (struct H_el *) 0;*/ + " trpt->ostate = (trpt-1)->ostate;", "#endif", "#ifdef VERI", " if ((trpt->tau&4) || ((trpt-1)->tau&128))", "#endif", " if (boq == -1) { /* if not mid-rv */", "#ifndef SAFETY", - " /* this check should now be redundant", - " * because the seed state also appears", - " * on the 1st dfs stack and would be", - " * matched in hstore below", - " */", +#if 0 + we want to skip nrpr, nrqs, _a_t and cnt[NFAIR] (in the case of fairness) + this is calculated in S_A, but S_A subtracts 2 bytes, + because nrpr and nrqs are masked in the default state comparisons + so we add those two bytes back here + -- in default comparisons (h_store) we skip _a_t and cnt in the + -- first comparison to find a match on the base-state + -- the _a_t and cnt fields are then separately updated if there was + -- a match on the base state +#endif " if ((now._a_t&1) && depth > A_depth)", - " { if (!memcmp((char *)&A_Root, ", - " (char *)&now, vsize))", + " { int delta = S_A + 2;", + " if (!memcmp((char *)&A_Root + delta, ", + " (char *)&now + delta, vsize - delta))", " {", - " depthfound = A_depth;", - "#ifdef CHECK", - " printf(\"matches seed\\n\");", - "#endif", - "#ifdef NP", - " uerror(\"non-progress cycle\");", - "#else", - " uerror(\"acceptance cycle\");", - "#endif", - " goto Up;", + "#ifndef NOFAIR", + " if (fairness && now._cnt[1] != 1) /* was > 1 */", + " {", + " #ifdef CHECK", + " printf(\"\tfairness count non-zero\\n\");", + " #endif", + " /* treat as new state */", + " } else", + "#endif", + " { depthfound = A_depth;", + " #ifdef CHECK", + " printf(\"matches seed\\n\");", + " #endif", + " #ifdef NP", + " uerror(\"non-progress cycle\");", + " #else", + " uerror(\"acceptance cycle\");", + " #endif", + " #if NCORE>1 && defined(FULL_TRAIL)", + " if (upto > 0)", + " { Pop_Stack_Tree();", + " }", + " #endif", + " goto Up;", + " } }", + " #ifdef CHECK", + " else", + " {", + " printf(\"not seed\\n\");", " }", - "#ifdef CHECK", - " printf(\"not seed\\n\");", - "#endif", + " #endif", " }", "#endif", " if (!(trpt->tau&8)) /* if no atomic move */", " {", + "#if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)", + " uchar was_last = now._last;", + " now._last = 0; /* value not stored */", + "#endif", "#ifdef BITSTATE", "#ifdef CNTRSTACK", /* -> bitstate, reduced, safety */ - " II = bstore((char *)&now, vsize);", - " trpt->j6 = j1; trpt->j7 = j2;", - " JJ = LL[j1] && LL[j2];", + " #if defined(BCS) && defined(STORE_CTX)", + " { int xj;", + " for (xj = trpt->sched_limit; xj <= sched_max; xj++)", + " { now._ctx = xj;", + " II = b_store((char *)&now, vsize);", + " trpt->j6 = j1_spin; trpt->j7 = j2_spin;", + " JJ = LL[j1_spin] && LL[j2_spin];", + " if (II != 0) { break; }", + " }", + " now._ctx = 0; /* just in case */", + " }", + " #else", + " II = b_store((char *)&now, vsize);", + " trpt->j6 = j1_spin; trpt->j7 = j2_spin;", + " JJ = LL[j1_spin] && LL[j2_spin];", + " #endif", "#else", - "#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 */ + " #ifdef FULLSTACK", /* b_store after onstack_now, to preserve j1-j4 */ + " #if defined(BCS) && defined(STORE_CTX)", + " { int xj;", + " now._ctx = 0;", + " JJ = onstack_now();", /* mangles j1 */ + " for (xj = trpt->sched_limit; xj <= sched_max; xj++)", + " { now._ctx = xj;", + " II = b_store((char *)&now, vsize);", /* sets j1-j4 */ + " if (II != 0) { break; }", + " }", + " now._ctx = 0;", + " }", + " #else", + " JJ = onstack_now();", /* mangles j1 */ + " II = b_store((char *)&now, vsize);", /* sets j1-j4 */ + " #endif", + " #else", + " #if defined(BCS) && defined(STORE_CTX)", + " { int xj;", + " for (xj = trpt->sched_limit; xj <= sched_max; xj++)", + " { now._ctx = xj;", + " II = b_store((char *)&now, vsize);", /* sets j1-j4 */ + " JJ = II; /* worstcase guess for p.o. - order corrected in 5.2.1 */", + " if (II != 0) { break; }", + " }", + " now._ctx = 0;", + " }", + " #else", + " II = b_store((char *)&now, vsize);", /* sets j1-j4 */ + " JJ = II; /* worstcase guess for p.o. - order corrected in 5.2.1 */", + " #endif", + " #endif", "#endif", "#else", "#ifdef MA", - " II = gstore((char *)&now, vsize, 0);", + " II = g_store((char *)&now, vsize, 0);", "#ifndef FULLSTACK", " JJ = II;", "#else", " JJ = (II == 2)?1:0;", "#endif", "#else", - " II = hstore((char *)&now, vsize);", + " II = h_store((char *)&now, vsize);", + " /* @hash j1_spin II */", "#ifdef FULLSTACK", " JJ = (II == 2)?1:0;", "#endif", "#endif", "#endif", " kk = (II == 1 || II == 2);", + /* actually, BCS implies HAS_LAST */ + "#if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)", + " now._last = was_last; /* restore value */", + "#endif", + /* II==0 new state */ /* II==1 old state */ /* II==2 on current dfs stack */ /* II==3 on 1st dfs stack */ "#ifndef SAFETY", - - " if (!fairness && a_cycles)", + /* with multicore we don't know which stack its on */ + /* with HC there's a small chance of a false match - example fifoq 2012 */ + "#if !defined(HC) && (NCORE==1 || defined (SEP_STATE))", " if (II == 2 && ((trpt->o_pm&2) || ((trpt-1)->o_pm&2)))", - " { II = 3; /* Schwoon & Esparza 2005, Gastin&Moro 2004 */", - "#ifdef VERBOSE", + " #ifndef NOFAIR", + " if (a_cycles && !fairness) /* 5.1.6 -- example by Hirofumi Watanabe */", + " #endif", + " if (depth > A_depth) /* forum example by adl */", + " {", + " II = 3; /* Schwoon & Esparza 2005, Gastin&Moro 2004 */", + "#ifdef VERBOSE", " printf(\"state match on dfs stack\\n\");", - "#endif", + "#endif", " goto same_case;", " }", - + "#endif", "#if defined(FULLSTACK) && defined(BITSTATE)", " if (!JJ && (now._a_t&1) && depth > A_depth)", - " { int oj1 = j1;", + " { int oj1 = j1_spin;", " uchar o_a_t = now._a_t;", " now._a_t &= ~(1|16|32);", /* 1st stack */ - " if (onstack_now())", /* changes j1 */ + " if (onstack_now())", /* changes j1_spin */ " { II = 3;", "#ifdef VERBOSE", " printf(\"state match on 1st dfs stack\\n\");", "#endif", " }", " now._a_t = o_a_t;", /* restore */ - " j1 = oj1;", + " j1_spin = oj1;", " }", "#endif", " if (II == 3 && a_cycles && (now._a_t&1))", " {", "#ifndef NOFAIR", - " if (fairness && now._cnt[1] > 1) /* was != 0 */", + " if (fairness && now._cnt[1] != 1) /* was > 1 */", " {", - "#ifdef VERBOSE", + " #ifdef CHECK", " printf(\"\tfairness count non-zero\\n\");", - "#endif", + " #endif", " II = 0;", /* treat as new state */ " } else", "#endif", @@ -1741,47 +2880,114 @@ static char *Code2c[] = { "#else", " uerror(\"acceptance cycle\");", "#endif", + "#if NCORE>1 && defined(FULL_TRAIL)", + " if (upto > 0)", + " { Pop_Stack_Tree();", + " }", + "#endif", " goto Up;", " }", " }", "#endif", "#ifndef NOREDUCE", - "#ifndef SAFETY", + " #ifndef SAFETY", + " #if NCORE>1 && !defined(SEP_STATE) && defined(V_PROVISO)", + " if (II != 0 && (!Lstate || Lstate->cpu_id < core_id))", + " { (trpt-1)->tau |= 16;", /* treat as a stack state */ + " }", + " #endif", " if ((II && JJ) || (II == 3))", " { /* marker for liveness proviso */", - " (trpt-1)->tau |= 16;", + " #ifndef LOOPSTATE", + " (trpt-1)->tau |= 16;", /* truncated on stack */ + " #endif", " truncs2++;", " }", "#else", + " #if NCORE>1 && !defined(SEP_STATE) && defined(V_PROVISO)", + " if (!(II != 0 && (!Lstate || Lstate->cpu_id < core_id)))", + " { /* treat as stack state */", + " (trpt-1)->tau |= 16;", + " } else", + " { /* treat as non-stack state */", + " (trpt-1)->tau |= 64;", + " }", + " #endif", " if (!II || !JJ)", " { /* successor outside stack */", " (trpt-1)->tau |= 64;", " }", - "#endif", + " #endif", + "#endif", + "#if defined(BCS) && (defined(NOREDUCE) || !defined(SAFETY))", + /* needed for BCS - cover cases where it would not otherwise be set */ + " if (!II || !JJ)", + " { (trpt-1)->tau |= 64;", + " }", "#endif", " if (II)", " { truncs++;", + "#if NCORE>1 && defined(FULL_TRAIL)", + " if (upto > 0)", + " { Pop_Stack_Tree();", + " if (depth == 0)", + " { return;", + " } }", + "#endif", " goto Up;", " }", " if (!kk)", - " { nstates++;", - " if ((unsigned long) nstates%%1000000 == 0)", - " snapshot();", + " { static long sdone = (long) 0; long ndone;", + " nstates++;", + "#if defined(ZAPH) && defined(BITSTATE)", + " zstates += (double) hfns;", + "#endif", + " ndone = (ulong) (nstates/(freq));", + " if (ndone != sdone)", + " { snapshot();", + " sdone = ndone;", + "#if defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(MA)", + " if (nstates > ((double)(ONE_L<<(ssize+1))))", + " { void resize_hashtable(void);", + " resize_hashtable();", + " }", + "#endif", + "#if defined(ZAPH) && defined(BITSTATE)", + " if (zstates > ((double)(ONE_L<<(ssize-2))))", + " { /* more than half the bits set */", + " void zap_hashtable(void);", + " zap_hashtable();", + " zstates = 0;", + " }", + "#endif", + " }", "#ifdef SVDUMP", " if (vprefix > 0)", + " #ifdef SHO", /* Store Hash Only */ + " /* always use the same hashfunction, for consistency across runs */", + " if (HASH_NR != 0)", + " { int oh = HASH_NR;", + " HASH_NR = 0;", + " d_hash((uchar *) &now, vsize); /* SHO - set K1 */", + " HASH_NR = oh;", + " }", + " if (write(svfd, (uchar *) &K1, sizeof(ulong)) != sizeof(ulong))", + " #else", " if (write(svfd, (uchar *) &now, vprefix) != vprefix)", - " { fprintf(efd, \"writing %%s.svd failed\\n\", Source);", + " #endif", + " { fprintf(efd, \"writing %%s.svd failed\\n\", PanSource);", " wrapup();", " }", "#endif", "#if defined(MA) && defined(W_XPT)", - " if ((unsigned long) nstates%%W_XPT == 0)", + " if ((ulong) nstates%%W_XPT == 0)", " { void w_xpoint(void);", " w_xpoint();", " }", "#endif", " }", + "#if defined(FULLSTACK) || defined(CNTRSTACK)", " onstack_put();", "#ifdef DEBUG2", @@ -1793,10 +2999,13 @@ static char *Code2c[] = { " printf(\"%%d: putting\\n\", depth);", "#endif", "#endif", + "#else", + " #if NCORE>1", + " trpt->ostate = Lstate;", + " #endif", "#endif", " } }", - " if (depth > mreached)", " mreached = depth;", "#ifdef VERI", @@ -1809,40 +3018,56 @@ static char *Code2c[] = { "#endif", "#ifdef VERI", " if (now._nr_pr == 0) /* claim terminated */", - " uerror(\"end state in claim reached\");", - " check_claim(((P0 *)pptr(0))->_p);", + " { uerror(\"end state in claim reached\");", + " }", + " if (stopstate[((Pclaim *)pptr(0))->_t][((Pclaim *)pptr(0))->_p])", + " { uerror(\"end state in claim reached\");", + " }", "Stutter:", " if (trpt->tau&4) /* must make a claimmove */", " {", - - "#ifndef NOFAIR", + " #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", + "#ifdef DEBUG", " printf(\"%%3d: fairness Rule 3.: _a_t = %%d\\n\",", - " depth, now._a_t);", - "#endif", + " (int) depth, now._a_t);", + "#endif", " }", - "#endif", - + " #endif", " II = 0; /* never */", " goto Veri0;", " }", "#endif", + "#ifdef PERMUTED", + " if (reversing&2)", + " { seed = rand();", + " p_reorder(seed);", + " }", + "#endif", "#ifndef NOREDUCE", " /* Look for a process with only safe transitions */", " /* (special rules apply in the 2nd dfs) */", -"#ifdef SAFETY", - " if (boq == -1 && From != To)", -"#else", - "/* implied: #ifdef FULLSTACK */", " if (boq == -1 && From != To", + "", + "#ifdef SAFETY", + " #if NCORE>1", + " && (depth < z_handoff)", /* not for border states */ + " #endif", + " )", + "#else", + " #if NCORE>1", + " && ((a_cycles) || (!a_cycles && depth < z_handoff))", + " #endif", + " #ifdef BCS", + " && (sched_max > 0 || depth > BASE)", /* no po in initial state if -L0 */ + " #endif", " && (!(now._a_t&1)", " || (a_cycles &&", - "#ifndef BITSTATE", + " #ifndef BITSTATE", "#ifdef MA", "#ifdef VERI", " !((trpt-1)->proviso))", @@ -1852,63 +3077,58 @@ static char *Code2c[] = { "#else", "#ifdef VERI", " (trpt-1)->ostate &&", - " !(((char *)&((trpt-1)->ostate->state))[0] & 128))", + " !(((char *)&((trpt-1)->ostate->state))[0] & 128))", /* proviso bit in _a_t */ "#else", " !(((char *)&(trpt->ostate->state))[0] & 128))", "#endif", "#endif", - "#else", + " #else", "#ifdef VERI", " (trpt-1)->ostate &&", " (trpt-1)->ostate->proviso == 0)", "#else", " trpt->ostate->proviso == 0)", "#endif", - "#endif", + " #endif", " ))", - "/* #endif */", -"#endif", - " for (II = From; II >= To; II -= 1)", - " {", - "Resume: /* pick up here if preselect fails */", - " this = pptr(II);", - " tt = (int) ((P0 *)this)->_p;", - " ot = (uchar) ((P0 *)this)->_t;", - " if (trans[ot][tt]->atom & 8)", - " { t = trans[ot][tt];", - " if (t->qu[0] != 0)", - " { Ccheck++;", - " if (!q_cond(II, t))", - " continue;", - " Cholds++;", - " }", - " From = To = II;", - "#ifdef NIBIS", - " t->om = 0;", + "#endif", /* SAFETY */ + " /* attempt Partial Order Reduction as preselect moves */", + "#ifdef BCS", + " if (trpt->sched_limit < sched_max)", /* po only if we can switch */ "#endif", - " trpt->tau |= 32; /* preselect marker */", - "#ifdef DEBUG", - "#ifdef NIBIS", - " printf(\"%%3d: proc %%d Pre\", depth, II);", - " printf(\"Selected (om=%%d, tau=%%d)\\n\", ", - " t->om, trpt->tau);", - "#else", - " printf(\"%%3d: proc %%d PreSelected (tau=%%d)\\n\", ", - " depth, II, trpt->tau);", - "#endif", - "#endif", - " goto Again;", - " }", - " }", + " { for ALL_P {", /* PO preselect */ + "Resume: /* pick up here if preselect fails */", + " this = pptr(II);", + " tt = (int) ((P0 *)this)->_p;", + " ot = (uchar) ((P0 *)this)->_t;", + " if (trans[ot][tt]->atom & 8)", + " { t = trans[ot][tt];", + " if (t->qu[0] != 0)", + " { Ccheck++;", + " if (!q_cond(II, t))", + " { continue;", + " }", + " Cholds++;", + " }", + " From = To = II; /* preselect process */", + "#ifdef NIBIS", + " t->om = 0;", + "#endif", + " trpt->tau |= 32; /* preselect marker */", + "#ifdef DEBUG", + " printf(\"%%3ld: proc %%d PreSelected (tau=%%d)\\n\", ", + " depth, II, trpt->tau);", + "#endif", + " goto Again;", + " } else", + " { continue;", + " } } }", " 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 */", - + " trpt->o_pm &= ~(8|16|32|64); /* clear fairness-marks */", "#ifndef NOFAIR", " if (fairness && boq == -1", "#ifdef VERI", @@ -1917,36 +3137,136 @@ static char *Code2c[] = { " && !(trpt->tau&8))", " { /* A_bit = 1; Cnt = N in acc states with A_bit 0 */", " if (!(now._a_t&2))", /* A-bit not set */ - " {", - " if (a_cycles && (trpt->o_pm&2))", + " { if (a_cycles && (trpt->o_pm&2))", " { /* Accepting state */", " now._a_t |= 2;", - " now._cnt[now._a_t&1] = now._nr_pr + 1;", /* NEW +1 */ + " now._cnt[now._a_t&1] = now._nr_pr + 1;", " trpt->o_pm |= 8;", "#ifdef DEBUG", - " printf(\"%%3d: fairness Rule 1: cnt=%%d, _a_t=%%d\\n\",", + " printf(\"%%3ld: fairness Rule 1: cnt=%%d, _a_t=%%d\\n\",", " depth, now._cnt[now._a_t&1], now._a_t);", "#endif", " }", " } else", /* A-bit set */ " { /* A_bit = 0 when Cnt 0 */", - " if (now._cnt[now._a_t&1] == 1)", /* NEW: 1 iso 0 */ - " { now._a_t &= ~2;", /* reset a-bit */ - " now._cnt[now._a_t&1] = 0;", /* NEW: reset cnt */ + " if (now._cnt[now._a_t&1] == 1)", + " { now._a_t &= ~2;", /* reset a-bit */ + " now._cnt[now._a_t&1] = 0;", " trpt->o_pm |= 16;", "#ifdef DEBUG", - " printf(\"%%3d: fairness Rule 3: _a_t = %%d\\n\",", + " printf(\"%%3ld: fairness Rule 3: _a_t = %%d\\n\",", " depth, now._a_t);", "#endif", " } } }", "#endif", - " for (II = From; II >= To; II -= 1)", - " {", + "#ifdef BCS", /* bounded context switching */ + " trpt->bcs = trpt->b_pno = 0; /* initial */", + " if (From != To /* not a PO or atomic move */", + " && depth > BASE) /* there is a prior move */", + " { trpt->b_pno = now._last + BASE;", + " trpt->bcs = B_PHASE1;", + " #ifdef VERBOSE", + " printf(\"%%3ld: BCS phase 1 proc %%d limit %%d\\n\",", + " depth, trpt->b_pno, trpt->sched_limit);", + " #endif", + " /* allow only process b_pno to move in this phase */", + " }", + "c_switch: /* jumps here with bcs == B_PHASE2 with or wo B_FORCED added */", + " #ifdef VERBOSE", + " printf(\"%%3ld: BCS c_switch phase=%%d pno=%%d [forced %%d]\\n\",", + " depth, trpt->bcs, trpt->b_pno, (trpt->bcs&B_FORCED)?1:0);", + " #endif", + "#endif", + + "#ifdef P_RAND", + " trpt->p_left = CNT_P;", + " if (trpt->p_left > 1)", + " { trpt->p_skip = rand() %% (trpt->p_left);", + " } else", + " { trpt->p_skip = -1;", + " }", + "r_switch:", + " #ifdef VERBOSE", + " printf(\"%%3ld: P_RAND r_switch p_skip=%%d p_left=%%d\\n\",", + " depth, trpt->p_skip, trpt->p_left);", + " #endif", + "#endif", + + " for ALL_P {", /* Main Loop */ + "#ifdef PERMUTED", + " if (reversing&2)", + " { oII = II;", + " if (From != To)", /* not atomic or preselected */ + " { II = get_permuted(II);", + " } }", + "#endif", + "#ifdef P_RAND", + " if (trpt->p_skip >= 0)", + " { trpt->p_skip--; /* skip random nr of procs */", + " #ifdef VERBOSE", + " printf(\"%%3ld: P_RAND skipping %%d [new p_skip=%%d p_left=%%d]\\n\",", + " depth, II, trpt->p_skip, trpt->p_left);", + " #endif", + " CONTINUE0;", + " }", + " if (trpt->p_left == 0)", + " {", + " #ifdef VERBOSE", + " printf(\"%%3ld: P_RAND done at %%d\\n\", depth, II);", + " #endif", + " break; /* done */", + " }", + " #ifdef VERBOSE", + " printf(\"%%3ld: P_RAND explore %%d [p_left=%%d]\\n\",", + " depth, II, trpt->p_left);", + " #endif", + " trpt->p_left--;", + "#endif", + "#if SYNC", " /* no rendezvous with same proc */", - " if (boq != -1 && trpt->pr == II) continue;", + " if (boq != -1 && trpt->pr == II)", + " { CONTINUE0;", + " }", "#endif", + + "#ifdef BCS", /* never claim with II==0 cannot get here */ + " if ((trpt->bcs & B_PHASE1)", + " && trpt->b_pno != II)", + " {", + " #ifdef VERBOSE", + " printf(\"%%3ld: BCS NotPre II=%%d bcs=%%d pno=%%d [forced %%d]\\n\",", + " depth, II, trpt->bcs, trpt->b_pno, (trpt->bcs&B_FORCED)?1:0);", + " #endif", + " CONTINUE0;", /* avoid context switch */ + " }", + " #ifdef VERBOSE", + " else if ((trpt->bcs & B_PHASE1) && trpt->b_pno == II)", + " printf(\"%%3ld: BCS IsPre II=%%d bcs=%%d pno=%%d [forced %%d]\\n\",", + " depth, II, trpt->bcs, trpt->b_pno, (trpt->bcs&B_FORCED)?1:0);", + " #endif", + + " if (trpt->bcs & B_PHASE2) /* 2nd phase */", + " { if (trpt->b_pno == II) /* was already done in phase 1 */", + " {", + " #ifdef VERBOSE", + " printf(\"%%3ld: BCS NoRepeat II=%%d bcs=%%d pno=%%d [forced %%d]\\n\",", + " depth, II, trpt->bcs, trpt->b_pno, (trpt->bcs&B_FORCED)?1:0);", + " #endif", + " CONTINUE0;", + " }", + " if (!(trpt->bcs & B_FORCED) /* unless forced */", + " && trpt->sched_limit >= sched_max)", + " {", + " #ifdef VERBOSE", + " printf(\"%%3ld: BCS Bound II=%%d bcs=%%d pno=%%d [forced %%d]\\n\",", + " depth, II, trpt->bcs, trpt->b_pno, (trpt->bcs&B_FORCED)?1:0);", + " #endif", + " CONTINUE0; /* enforce bound */", + " } }", + "#endif", + "#ifdef VERI", "Veri0:", "#endif", @@ -1967,8 +3287,10 @@ static char *Code2c[] = { " { if (t->qu[0] == 0", /* unconditional */ " || q_cond(II, t))", /* true condition */ " { _m = t->om;", - " if (_m>_n||(_n>3&&_m!=0)) _n=_m;", - " continue; /* did it before */", + " if (_m>_n||(_n>3&&_m!=0))", + " { _n=_m;", + " }", + " CONTINUE0; /* did it before */", " } }", "#endif", " trpt->o_pm &= ~1; /* no move in this pid yet */", @@ -1990,16 +3312,26 @@ static char *Code2c[] = { " now._cnt[now._a_t&1] = 1;", "#endif", "#ifdef DEBUG", - " printf(\"%%3d: proc %%d fairness \", depth, II);", + " printf(\"%%3ld: proc %%d fairness \", depth, II);", " printf(\"Rule 2: --cnt to %%d (%%d)\\n\",", " now._cnt[now._a_t&1], now._a_t);", "#endif", " trpt->o_pm |= (32|64);", " }", "#endif", - "#ifdef HAS_PROVIDED", - " if (!provided(II, ot, tt, t)) continue;", + + "#ifdef HAS_PRIORITY", + " if (!highest_priority(((P0 *)this)->_pid, II, t))", + " { CONTINUE0;", + " }", + "#else", + " #ifdef HAS_PROVIDED", + " if (!provided(II, ot, tt, t))", + " { CONTINUE0;", + " }", + " #endif", "#endif", + " /* check all trans of proc II - escapes first */", "#ifdef HAS_UNLESS", " trpt->e_state = 0;", @@ -2007,27 +3339,31 @@ static char *Code2c[] = { " (trpt+1)->pr = (uchar) II;", /* for uerror */ " (trpt+1)->st = tt;", - "#ifdef RANDOMIZE", + "#ifdef T_RAND", " for (ooi = eoi = 0, t = trans[ot][tt]; t; t = t->nxt, ooi++)", - " if (strcmp(t->tp, \"else\") == 0)", - " eoi++;", - "", - " if (eoi)", + " { if (strcmp(t->tp, \"else\") == 0", + " #ifdef HAS_UNLESS", + " || t->e_trans != 0", + " #endif", + " )", + " { eoi++;", /* no break, must count ooi */ + " } }", + " if (eoi > 0)", " { t = trans[ot][tt];", - "#ifdef VERBOSE", - " printf(\"randomizer: suppressed, saw else\\n\");", - "#endif", - " } else", + " #ifdef VERBOSE", + " printf(\"randomizer: suppressed, saw else or escape\\n\");", + " #endif", + " } else if (ooi > 0)", " { eoi = rand()%%ooi;", - "#ifdef VERBOSE", + " #ifdef VERBOSE", " printf(\"randomizer: skip %%d in %%d\\n\", eoi, ooi);", - "#endif", + " #endif", " for (t = trans[ot][tt]; t; t = t->nxt)", " if (eoi-- <= 0) break;", " }", - "DOMORE:", + "domore:", " for ( ; t && ooi > 0; t = t->nxt, ooi--)", - "#else", + "#else", /* ie dont randomize */ " for (t = trans[ot][tt]; t; t = t->nxt)", "#endif", " {", @@ -2045,49 +3381,83 @@ static char *Code2c[] = { " break;", " }", "#endif", + " #if defined(TRIX) && !defined(TRIX_ORIG) && !defined(BFS)", + " (trpt+1)->p_bup = now._ids_[II];", + " #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))) continue;", + " if (!(_m = do_transit(t, II)))", + " { continue;", + " }", + "#endif", + "#ifdef BCS", + " if (depth > BASE", /* has prior move */ + " && II >= BASE", /* not claim */ + " && From != To", /* not atomic or po */ + " #ifndef BCS_NOFIX", + " /* added 5.2.5: prior move was not po */", + " && !((trpt-(BASE+1))->tau & 32)", + " #endif", + " && boq == -1", /* not rv */ + " && (trpt->bcs & B_PHASE2)", + " && trpt->b_pno != II /* context switch */", /* redundant */ + " && !(trpt->bcs & B_FORCED)) /* unless forced */", + " { (trpt+1)->sched_limit = 1 + trpt->sched_limit;", + " #ifdef VERBOSE", + " printf(\"%%3ld: up sched count to %%d\\n\", depth, (trpt+1)->sched_limit);", + " #endif", + " } else", + " { (trpt+1)->sched_limit = trpt->sched_limit;", + " #ifdef VERBOSE", + " printf(\"%%3ld: keep sched count at %%d\\n\", depth, (trpt+1)->sched_limit);", + " #endif", + " }", "#endif", " if (boq == -1)", -"#ifdef CTL", + "#ifdef CTL", " /* for branching-time, can accept reduction only if */", " /* the persistent set contains just 1 transition */", " { if ((trpt->tau&32) && (trpt->o_pm&1))", - " trpt->tau |= 16;", + " trpt->tau |= 16;", /* CTL */ " trpt->o_pm |= 1; /* we moved */", " }", -"#else", + "#else", " trpt->o_pm |= 1; /* we moved */", -"#endif", + "#endif", + + "#ifdef LOOPSTATE", + " if (loopstate[ot][tt])", + " {", + "#ifdef VERBOSE", + " printf(\"exiting from loopstate:\\n\");", + "#endif", + " trpt->tau |= 16;", /* exiting loopstate */ + " cnt_loops++;", + " }", + "#endif", + "#ifdef PEG", " peg[t->forw]++;", "#endif", - "#if defined(VERBOSE) || defined(CHECK)", "#if defined(SVDUMP)", - " printf(\"%%3d: proc %%d exec %%d \\n\", ", - " depth, II, t->t_id);", + " cpu_printf(\"%%3ld: proc %%d exec %%d \\n\", depth, II, t->t_id);", "#else", - " printf(\"%%3d: proc %%d exec %%d, \", ", - " depth, II, t->forw);", - " printf(\"%%d to %%d, %%s %%s %%s\", ", - " tt, t->st, t->tp,", + " cpu_printf(\"%%3ld: proc %%d exec %%d, %%d to %%d, %%s %%s %%s %%saccepting [tau=%%d]\\n\", ", + " depth, II, t->forw, 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\",", + " (boq != -1)?\"rendez-vous\":\"\",", " (trpt->o_pm&2)?\"\":\"non-\", trpt->tau);", + "#ifdef HAS_UNLESS", + " if (t->e_trans)", + " cpu_printf(\"\\t(escape to state %%d)\\n\", t->st);", "#endif", - "#ifdef RANDOMIZE", - " printf(\" randomizer %%d\\n\", ooi);", + "#endif", + "#ifdef T_RAND", + " cpu_printf(\"\\t(randomizer %%d)\\n\", ooi);", "#endif", "#endif", @@ -2143,9 +3513,16 @@ static char *Code2c[] = { " trpt->o_ot = ot; trpt->o_tt = tt;", " trpt->o_To = To; trpt->o_m = _m;", " trpt->tau = 0;", -"#ifdef RANDOMIZE", + "#ifdef PERMUTED", + " if (reversing&2)", + " { trpt->seed = seed;", + " trpt->oII = oII;", + " }", + "#endif", + + "#if defined(T_RAND) && !defined(BFS)", " trpt->oo_i = ooi;", -"#endif", + "#endif", " if (boq != -1 || (t->atom&2))", " { trpt->tau |= 8;", "#ifdef VERI", @@ -2171,30 +3548,76 @@ static char *Code2c[] = { " if (boq == -1 && (t->atom&2))", " { From = To = II; nlinks++;", " } else", - " { From = now._nr_pr-1; To = BASE;", + " { From = FROM_P; To = UPTO_P;", " }", + "#if NCORE>1 && defined(FULL_TRAIL)", + " if (upto > 0)", + " { Push_Stack_Tree(II, t->t_id);", + " }", + "#endif", + "#ifdef TRIX", + " if (processes[II])", /* last move could have been a delproc */ + " { processes[II]->modified = 1; /* transition in II */", + " #ifdef V_TRIX", + " printf(\"%%4d: process %%d modified\\n\", depth, II);", + " } else", + " { printf(\"%%4d: process %%d modified but gone (%%p)\\n\",", + " depth, II, trpt);", + " #endif", + " }", + "#endif", " goto Down; /* pseudo-recursion */", "Up:", - "#ifdef CHECK", - " printf(\"%%d: Up - %%s\\n\", depth,", - " (trpt->tau&4)?\"claim\":\"program\");", + "#ifdef TRIX", + " #ifndef TRIX_ORIG", + " #ifndef BFS", + " now._ids_[trpt->pr] = trpt->p_bup;", + " #endif", + " #else", + " if (processes[trpt->pr])", + " {", + " processes[trpt->pr]->modified = 1; /* reverse move */", + " #ifdef V_TRIX", + " printf(\"%%4d: unmodify pr %%d (%%p)\\n\",", + " depth, trpt->pr, trpt);", + " } else", + " { printf(\"%%4d: unmodify pr %%d (gone) (%%p)\\n\",", + " depth, trpt->pr, trpt);", + " #endif", + " }", + " #endif", "#endif", - "#ifdef MA", - " if (depth <= 0) return;", - " /* e.g., if first state is old, after a restart */", + "#ifdef CHECK", + " cpu_printf(\"%%d: Up - %%s\\n\", depth,", + " (trpt->tau&4)?\"claim\":\"program\");", + "#endif", + "#if NCORE>1", + " iam_alive();", + " #ifdef USE_DISK", + " mem_drain();", + " #endif", + "#endif", + "#if defined(MA) || NCORE>1", + " if (depth <= 0) return;", + " /* e.g., if first state is old, after a restart */", "#endif", "#ifdef SC", - " if (CNT1 > CNT2", - " && depth < hiwater - (HHH-DDD) + 2)", - " {", - " trpt += DDD;", - " disk2stack();", - " maxdepth -= DDD;", - " hiwater -= DDD;", - "if(verbose)", - "printf(\"unzap %%d: %%d\\n\", CNT2, hiwater);", - " }", + " if (CNT1 > CNT2", + " && depth < hiwater - (HHH-DDD) - 2)", /* 5.1.6: was + 2 */ + " {", + " trpt += DDD;", + " disk2stack();", + " maxdepth -= DDD;", + " hiwater -= DDD;", + " if(verbose)", + " printf(\"unzap %%ld: %%ld\\n\", CNT2, hiwater);", + " }", + "#endif", + + "#ifndef SAFETY", /* moved earlier in version 5.2.5 */ + " if ((now._a_t&1) && depth <= A_depth)", + " return; /* to checkcycles() */", "#endif", "#ifndef NOFAIR", @@ -2203,7 +3626,7 @@ static char *Code2c[] = { " _n = 1; trpt->o_pm &= ~128;", " depth--; trpt--;", "#if defined(VERBOSE) || defined(CHECK)", - " printf(\"%%3d: reversed fairness default move\\n\", depth);", + " printf(\"%%3ld: reversed fairness default move\\n\", depth);", "#endif", " goto Q999;", " }", @@ -2211,7 +3634,7 @@ static char *Code2c[] = { "#ifdef HAS_LAST", "#ifdef VERI", - " { int d; Trail *trl;", + " { long d; Trail *trl;", " now._last = 0;", " for (d = 1; d < depth; d++)", " { trl = getframe(depth-d); /* was (trpt-d) */", @@ -2226,61 +3649,63 @@ static char *Code2c[] = { "#ifdef EVENT_TRACE", " now._event = trpt->o_event;", "#endif", - "#ifndef SAFETY", - " if ((now._a_t&1) && depth <= A_depth)", - " return; /* to checkcycles() */", - "#endif", " t = trpt->o_t; _n = trpt->o_n;", " ot = trpt->o_ot; II = trpt->pr;", - " tt = trpt->o_tt; this = pptr(II);", + " tt = trpt->o_tt; this = Pptr(II);", " To = trpt->o_To; _m = trpt->o_m;", -"#ifdef RANDOMIZE", + "#ifdef PERMUTED", + " if (reversing&2)", + " { seed = trpt->seed;", + " oII = trpt->oII;", + " }", + "#endif", + "#if defined(T_RAND) && !defined(BFS)", " ooi = trpt->oo_i;", -"#endif", + "#endif", "#ifdef INLINE_REV", " _m = do_reverse(t, II, _m);", "#else", - "#include REVERSE_MOVES", + "#include BACKWARD_MOVES", "R999: /* jumps here when done */", "#endif", "#ifdef VERBOSE", - " 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);", + " cpu_printf(\"%%3ld: proc %%d reverses %%d, %%d to %%d\\n\",", + " depth, II, t->forw, tt, t->st);", + " cpu_printf(\"\\t%%s [abit=%%d,adepth=%%ld,tau=%%d,%%d]\\n\", ", + " t->tp, now._a_t, A_depth, trpt->tau, (trpt-1)->tau);", "#endif", "#ifndef NOREDUCE", " /* pass the proviso tags */", " if ((trpt->tau&8) /* rv or atomic */", " && (trpt->tau&16))", - " (trpt-1)->tau |= 16;", - "#ifdef SAFETY", + " (trpt-1)->tau |= 16;", /* pass upward */ + " #ifdef SAFETY", " if ((trpt->tau&8) /* rv or atomic */", " && (trpt->tau&64))", " (trpt-1)->tau |= 64;", + " #endif", "#endif", + + "#if defined(BCS) && (defined(NOREDUCE) || !defined(SAFETY))", + /* for BCS, cover cases where 64 is otherwise not handled */ + " if ((trpt->tau&8)", + " && (trpt->tau&64))", + " (trpt-1)->tau |= 64;", "#endif", + " depth--; trpt--;", + "", + "#ifdef NSUCC", + " trpt->n_succ++;", + "#endif", "#ifdef NIBIS", " (trans[ot][tt])->om = _m; /* head of list */", "#endif", " /* i.e., not set if rv fails */", " if (_m)", - " {", - "#if defined(VERI) && !defined(NP)", - " if (II == 0 && verbose && !reached[ot][t->st])", - " {", - " printf(\"depth %%d: Claim reached state %%d (line %%d)\\n\",", - " depth, t->st, src_claim [t->st]);", - " fflush(stdout);", - " }", - "#endif", - " reached[ot][t->st] = 1;", + " { reached[ot][t->st] = 1;", " reached[ot][tt] = 1;", " }", "#ifdef HAS_UNLESS", @@ -2291,18 +3716,18 @@ static char *Code2c[] = { " ((P0 *)this)->_p = tt;", " } /* all options */", - "#ifdef RANDOMIZE", + "#ifdef T_RAND", " if (!t && ooi > 0)", /* means we skipped some initial options */ " { t = trans[ot][tt];", - "#ifdef VERBOSE", + " #ifdef VERBOSE", " printf(\"randomizer: continue for %%d more\\n\", ooi);", - "#endif", - " goto DOMORE;", + " #endif", + " goto domore;", " }", - "#ifdef VERBOSE", + " #ifdef VERBOSE", " else", " printf(\"randomizer: done\\n\");", - "#endif", + " #endif", "#endif", "#ifndef NOFAIR", @@ -2312,12 +3737,12 @@ static char *Code2c[] = { " { if (trpt->o_pm&1)",/* it didn't block */ " {", "#ifdef VERI", - " if (now._cnt[now._a_t&1] == 1)", /* NEW: 1 iso 0 */ - " now._cnt[now._a_t&1] = 2;", /* NEW: 2 iso 1*/ + " if (now._cnt[now._a_t&1] == 1)", + " now._cnt[now._a_t&1] = 2;", "#endif", " now._cnt[now._a_t&1] += 1;", "#ifdef VERBOSE", - " printf(\"%%3d: proc %%d fairness \", depth, II);", + " printf(\"%%3ld: proc %%d fairness \", depth, II);", " printf(\"undo Rule 2, cnt=%%d, _a_t=%%d\\n\",", " now._cnt[now._a_t&1], now._a_t);", "#endif", @@ -2326,32 +3751,77 @@ static char *Code2c[] = { " { if (_n > 0)", /* a prev proc didn't */ " {", /* start over */ " trpt->o_pm &= ~64;", - " II = From+1;", + " II = INI_P;", /* after loop incr II == From */ " } } }", "#endif", - "#ifdef VERI", - " if (II == 0) break; /* never claim */", + " if (II == 0)", + " { break; /* never claim */", + " }", + "#endif", + " CONTINUE;", + " } /* ALL_P */", + + "#ifdef NSUCC", + " tally_succ(trpt->n_succ);", + "#endif", + + "#ifdef P_RAND", + " if (trpt->p_left > 0 && NDONE_P)", + " { trpt->p_skip = -1; /* probably rendundant */", + " #ifdef VERBOSE", + " printf(\"%%3ld: P_RAND -- explore remainder\\n\", depth);", + " #endif", + " goto r_switch; /* explore the remaining procs */", + " } else", + " {", + " #ifdef VERBOSE", + " printf(\"%%3ld: P_RAND -- none left\\n\", depth);", + " #endif", + " }", + "#endif", + + "#ifdef BCS", + " if (trpt->bcs & B_PHASE1)", + " { trpt->bcs = B_PHASE2; /* start 2nd phase */", + " if (_n == 0 || !(trpt->tau&64)) /* pre-move unexecutable or led to stackstate */", + " { trpt->bcs |= B_FORCED; /* forced switch */", + " }", + " #ifdef VERBOSE", + " printf(\"%%3ld: BCS move to phase 2, _n=%%d %%s\\n\", depth, _n,", + " (trpt->bcs & B_FORCED)?\"forced\":\"free\");", + " #endif", + " From = FROM_P; To = UPTO_P;", + " goto c_switch;", + " }", + "", + " if (_n == 0 /* no process could move */", + " && II >= BASE /* not the never claim */", + " && trpt->sched_limit >= sched_max)", + " { _n = 1;", + " #ifdef VERBOSE", + " printf(\"%%3ld: BCS not a deadlock\\n\", depth);", + " #endif", + " }", "#endif", - " } /* all processes */", "#ifndef NOFAIR", " /* Fairness: undo Rule 2 */", " if (trpt->o_pm&32) /* remains if proc blocked */", " {", "#ifdef VERI", - " if (now._cnt[now._a_t&1] == 1)", /* NEW: 1 iso 0 */ - " now._cnt[now._a_t&1] = 2;", /* NEW: 2 iso 1 */ + " if (now._cnt[now._a_t&1] == 1)", + " now._cnt[now._a_t&1] = 2;", "#endif", " now._cnt[now._a_t&1] += 1;", "#ifdef VERBOSE", - " printf(\"%%3d: proc -- fairness \", depth);", + " printf(\"%%3ld: proc -- fairness \", depth);", " printf(\"undo Rule 2, cnt=%%d, _a_t=%%d\\n\",", " now._cnt[now._a_t&1], now._a_t);", "#endif", " trpt->o_pm &= ~32;", " }", -"#ifndef NP", + "#ifndef NP", /* 12/97 non-progress cycles cannot be created * by stuttering extension, here or elsewhere */ @@ -2361,12 +3831,8 @@ static char *Code2c[] = { " && !(trpt->tau&4) /* in program move */", "#endif", " && !(trpt->tau&8) /* not an atomic one */", - "#ifdef OTIM", - " && ((trpt->tau&1) || endstate())", - "#else", - "#ifdef ETIM", - " && (trpt->tau&1) /* already tried timeout */", - "#endif", + "#ifdef ETIM", + " && (trpt->tau&1) /* already tried timeout */", "#endif", "#ifndef NOREDUCE", " /* see below */", @@ -2382,14 +3848,14 @@ static char *Code2c[] = { "#else", " trpt->tau = 0;", "#endif", - " From = now._nr_pr-1; To = BASE;", + " From = FROM_P; To = UPTO_P;", "#if defined(VERBOSE) || defined(CHECK)", - " printf(\"%%3d: fairness default move \", depth);", + " printf(\"%%3ld: fairness default move \", depth);", " printf(\"(all procs block)\\n\");", "#endif", " goto Down;", " }", -"#endif", + "#endif", "Q999: /* returns here with _n>0 when done */;", " if (trpt->o_pm&8)", @@ -2397,7 +3863,7 @@ static char *Code2c[] = { " now._cnt[now._a_t&1] = 0;", " trpt->o_pm &= ~8;", "#ifdef VERBOSE", - " printf(\"%%3d: fairness undo Rule 1, _a_t=%%d\\n\",", + " printf(\"%%3ld: fairness undo Rule 1, _a_t=%%d\\n\",", " depth, now._a_t);", "#endif", " }", @@ -2406,7 +3872,7 @@ static char *Code2c[] = { " now._cnt[now._a_t&1] = 1;", /* NEW: restore cnt */ " trpt->o_pm &= ~16;", "#ifdef VERBOSE", - " printf(\"%%3d: fairness undo Rule 3, _a_t=%%d\\n\",", + " printf(\"%%3ld: fairness undo Rule 3, _a_t=%%d\\n\",", " depth, now._a_t);", "#endif", " }", @@ -2414,35 +3880,41 @@ static char *Code2c[] = { "#ifndef NOREDUCE", "#ifdef SAFETY", - " /* preselected move - no successors 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, _n, trpt->tau);", - "#endif", + " #ifdef LOOPSTATE", + " /* at least one move that was preselected at this */", + " /* level, blocked or was a loop control flow point */", + " if ((trpt->tau&32) && (_n == 0 || (trpt->tau&16)))", + " #else", + " /* preselected move - no successors outside stack */", + " if ((trpt->tau&32) && !(trpt->tau&64))", + " #endif", + " { From = FROM_P; To = UPTO_P; /* undo From == To */", + " #ifdef DEBUG", + " printf(\"%%3ld: proc %%d UnSelected (_n=%%d, tau=%%d)\\n\", ", + " depth, II+1, _n, trpt->tau);", + " #endif", " _n = 0; trpt->tau &= ~(16|32|64);", - " if (II >= BASE) /* II already decremented */", - " goto Resume;", - " else", - " goto Again;", - " }", + + " if (MORE_P) /* II already restored and updated */", + " { goto Resume;", + " } else", + " { goto Again;", + " } }", "#else", " /* 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)))", " {", - "#ifdef DEBUG", - " printf(\"%%3d: proc %%d UnSelected (_n=%%d, tau=%%d)\\n\", ", - " depth, II+1, (int) _n, trpt->tau);", - "#endif", + " #ifdef DEBUG", + " printf(\"%%3ld: 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))", " {", - "#ifdef DEBUG", - " printf(\"%%3d: setting proviso bit\\n\", depth);", - "#endif", + " #ifdef DEBUG", + " printf(\"%%3ld: setting proviso bit\\n\", depth);", + " #endif", "#ifndef BITSTATE", "#ifdef MA", "#ifdef VERI", @@ -2466,27 +3938,26 @@ static char *Code2c[] = { " trpt->ostate->proviso = 1;", "#endif", "#endif", - " From = now._nr_pr-1; To = BASE;", + " From = FROM_P; To = UPTO_P;", " _n = 0; trpt->tau &= ~(16|32|64);", " goto Again; /* do full search */", " } /* else accept reduction */", " } else", - " { From = now._nr_pr-1; To = BASE;", + " { From = FROM_P; To = UPTO_P;", " _n = 0; trpt->tau &= ~(16|32|64);", - " if (II >= BASE) /* already decremented */", - " goto Resume;", - " else", - " goto Again;", - " } }", - "/* #endif */", + " if (MORE_P) /* II already updated */", + " { goto Resume;", + " } else", + " { goto Again;", + " } } }", "#endif", "#endif", " if (_n == 0 || ((trpt->tau&4) && (trpt->tau&2)))", " {", "#ifdef DEBUG", - " printf(\"%%3d: no move [II=%%d, tau=%%d, boq=%%d]\\n\",", - " depth, II, trpt->tau, boq);", + " cpu_printf(\"%%3ld: no move [II=%%d, tau=%%d, boq=%%d]\\n\",", + " depth, II, trpt->tau, boq);", "#endif", "#if SYNC", " /* ok if a rendez-vous fails: */", @@ -2494,18 +3965,14 @@ static char *Code2c[] = { "#endif", " /* ok if no procs or we're at maxdepth */", " if ((now._nr_pr == 0 && (!strict || qs_empty()))", - "#ifdef OTIM", - " || endstate()", - "#endif", - " || depth >= maxdepth-1) goto Done;", + " || depth >= maxdepth-1) goto Done; /* undo change from 5.2.3 */", " if ((trpt->tau&8) && !(trpt->tau&4))", " { trpt->tau &= ~(1|8);", " /* 1=timeout, 8=atomic */", - " From = now._nr_pr-1; To = BASE;", + " From = FROM_P; To = UPTO_P;", "#ifdef DEBUG", - " printf(\"%%3d: atomic step proc %%d \", depth, II+1);", - " printf(\"unexecutable\\n\");", + " cpu_printf(\"%%3ld: atomic step proc %%d unexecutable\\n\", depth, II+1);", "#endif", "#ifdef VERI", " trpt->tau |= 4; /* switch to claim */", @@ -2524,9 +3991,9 @@ static char *Code2c[] = { "#endif", " { trpt->tau |= 1;", " trpt->tau &= ~2;", - "#ifdef DEBUG", - " printf(\"%%d: timeout\\n\", depth);", - "#endif", + " #ifdef DEBUG", + " cpu_printf(\"%%d: timeout\\n\", depth);", + " #endif", " goto Stutter;", " } }", " else", @@ -2534,18 +4001,22 @@ static char *Code2c[] = { " if ((trpt->tau&8)", " && !((trpt-1)->tau&4))", "/* blocks inside an atomic */ goto BreakOut;", - "#ifdef DEBUG", - " printf(\"%%d: req timeout\\n\",", + " #ifdef DEBUG", + " cpu_printf(\"%%d: req timeout\\n\",", " depth);", - "#endif", + " #endif", " (trpt-1)->tau |= 2; /* request */", + " #if NCORE>1 && defined(FULL_TRAIL)", + " if (upto > 0)", + " { Pop_Stack_Tree();", + " }", + " #endif", " goto Up;", " }", "#else", - - "#ifdef DEBUG", - " printf(\"%%d: timeout\\n\", depth);", - "#endif", + " #ifdef DEBUG", + " cpu_printf(\"%%d: timeout\\n\", depth);", + " #endif", " trpt->tau |= 1;", " goto Again;", "#endif", @@ -2560,7 +4031,7 @@ static char *Code2c[] = { " { trpt->tau |= 4; /* claim stuttering */", " trpt->tau |= 128; /* stutter mark */", "#ifdef DEBUG", - " printf(\"%%d: claim stutter\\n\", depth);", + " cpu_printf(\"%%d: claim stutter\\n\", depth);", "#endif", " goto Stutter;", " }", @@ -2585,6 +4056,47 @@ static char *Code2c[] = { "Done:", " if (!(trpt->tau&8)) /* not in atomic seqs */", " {", + +"#ifndef MA", + "#if defined(FULLSTACK) || defined(CNTRSTACK)", + "#ifdef VERI", + " if (boq == -1", + " && (((trpt->tau&4) && !(trpt->tau&128))", + " || ( (trpt-1)->tau&128)))", + "#else", + " if (boq == -1)", + "#endif", + " {", + "#ifdef DEBUG2", + "#if defined(FULLSTACK)", + " printf(\"%%ld: zapping %%u (%%d)\\n\",", + " depth, trpt->ostate,", + " (trpt->ostate)?trpt->ostate->tagged:0);", + "#endif", + "#endif", + " onstack_zap();", + " }", + "#endif", +"#else", + "#ifdef VERI", + " if (boq == -1", + " && (((trpt->tau&4) && !(trpt->tau&128))", + " || ( (trpt-1)->tau&128)))", + "#else", + " if (boq == -1)", + "#endif", + " {", + "#ifdef DEBUG", + " printf(\"%%ld: zapping\\n\", depth);", + "#endif", + " onstack_zap();", + "#ifndef NOREDUCE", + " if (trpt->proviso)", + " g_store((char *) &now, vsize, 1);", + "#endif", + " }", +"#endif", + "#ifndef SAFETY", " if (_n != 0", /* we made a move */ "#ifdef VERI", @@ -2601,7 +4113,7 @@ static char *Code2c[] = { " if (fairness)", /* implies a_cycles */ " {", "#ifdef VERBOSE", - " printf(\"Consider check %%d %%d...\\n\",", + " cpu_printf(\"Consider check %%d %%d...\\n\",", " now._a_t, now._cnt[0]);", "#endif", #if 0 @@ -2624,54 +4136,23 @@ static char *Code2c[] = { " checkcycles();", " }", "#endif", -"#ifndef MA", - "#if defined(FULLSTACK) || defined(CNTRSTACK)", - "#ifdef VERI", - " if (boq == -1", - " && (((trpt->tau&4) && !(trpt->tau&128))", - " || ( (trpt-1)->tau&128)))", - "#else", - " if (boq == -1)", - "#endif", - " {", - "#ifdef DEBUG2", - "#if defined(FULLSTACK)", - " printf(\"%%d: zapping %%u (%%d)\\n\",", - " depth, trpt->ostate,", - " (trpt->ostate)?trpt->ostate->tagged:0);", - "#endif", - "#endif", - " onstack_zap();", - " }", - "#endif", -"#else", - "#ifdef VERI", - " if (boq == -1", - " && (((trpt->tau&4) && !(trpt->tau&128))", - " || ( (trpt-1)->tau&128)))", - "#else", - " if (boq == -1)", - "#endif", - " {", - "#ifdef DEBUG", - " printf(\"%%d: zapping\\n\", depth);", - "#endif", - " onstack_zap();", - "#ifndef NOREDUCE", - " if (trpt->proviso)", - " gstore((char *) &now, vsize, 1);", - "#endif", - " }", -"#endif", " }", - " if (depth > 0) goto Up;", + " if (depth > 0)", + " {", + "#if NCORE>1 && defined(FULL_TRAIL)", + " if (upto > 0)", + " { Pop_Stack_Tree();", + " }", + "#endif", + " goto Up;", + " }", "}\n", "#else", "void new_state(void) { /* place holder */ }", "#endif", /* BFS */ "", "void", - "assert(int a, char *s, int ii, int tt, Trans *t)", + "spin_assert(int a, char *s, int ii, int tt, Trans *t)", "{", " if (!a && !noasserts)", " { char bad[1024];", @@ -2688,169 +4169,214 @@ static char *Code2c[] = { "int", "Boundcheck(int x, int y, int a1, int a2, Trans *a3)", "{", - " assert((x >= 0 && x < y), \"- invalid array index\",", + " spin_assert((x >= 0 && x < y), \"- invalid array index\",", " a1, a2, a3);", " return x;", "}", "#endif", + "int do_hashgen = 0;", "void", "wrap_stats(void)", "{", " if (nShadow>0)", - " printf(\"%%8g states, stored (%%g visited)\\n\",", + " printf(\"%%9.8g states, stored (%%g visited)\\n\",", " nstates - nShadow, nstates);", " else", - " printf(\"%%8g states, stored\\n\", nstates);", + " printf(\"%%9.8g states, stored\\n\", nstates);", + "#ifdef BFS_PAR", + " if (bfs_punt > 0)", + " printf(\"%%9.8g states lost (lack of queue memory)\\n\", (double) bfs_punt);", + "#endif", "#ifdef BFS", - "#if SYNC", + " #if SYNC", " printf(\" %%8g nominal states (- rv and atomic)\\n\", nstates-midrv-nlinks+revrv);", " printf(\" %%8g rvs succeeded\\n\", midrv-failedrv);", - "#else", + " #else", " printf(\" %%8g nominal states (stored-atomic)\\n\", nstates-nlinks);", - "#endif", - "#ifdef DEBUG", + " #endif", + " #ifdef DEBUG", " printf(\" %%8g midrv\\n\", midrv);", " printf(\" %%8g failedrv\\n\", failedrv);", " printf(\" %%8g revrv\\n\", revrv);", + " #endif", "#endif", - "#endif", - " printf(\"%%8g states, matched\\n\", truncs);", + " printf(\"%%9.8g states, matched\\n\", truncs);", "#ifdef CHECK", - " printf(\"%%8g matches within stack\\n\",truncs2);", + " printf(\"%%9.8g matches within stack\\n\",truncs2);", "#endif", " if (nShadow>0)", - " printf(\"%%8g transitions (= visited+matched)\\n\",", + " printf(\"%%9.8g transitions (= visited+matched)\\n\",", " nstates+truncs);", " else", - " printf(\"%%8g transitions (= stored+matched)\\n\",", + " printf(\"%%9.8g transitions (= stored+matched)\\n\",", " nstates+truncs);", - " printf(\"%%8g atomic steps\\n\", nlinks);", + " printf(\"%%9.8g atomic steps\\n\", nlinks);", " if (nlost) printf(\"%%g lost messages\\n\", (double) nlost);", "", "#ifndef BITSTATE", - " printf(\"hash conflicts: %%g (resolved)\\n\", hcmp);", + " #ifndef MA", + " printf(\"hash conflicts: %%9.8g (resolved)\\n\", hcmp);", + " #if !defined(AUTO_RESIZE) && !defined(BFS_PAR)", + " if (hcmp > (double) (1< 1.0)", + " { fp = 100. / fp;", + " while (fp > 2.) { fi++; fp /= 2.; }", + " if (fi > 0)", + " { printf(\" (hint: rerun with -w%%d to reduce runtime)\",", + " ssize-fi);", + " } }", + " printf(\"\\n\");", + " }", + " #endif", + " #endif", "#else", "#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));", + " printf(\"\\nhash factor: %%4g (best if > 100.)\\n\\n\",", + " (double)(((double) udmem) * 8.0) / (double) nstates);", " else", -#endif - " printf(\"total bits available: %%8g (-w%%d)\\n\",", - " ((double) (1L << (ssize-4)) * 16.0), ssize);", + " printf(\"\\nhash factor: %%4g (best if > 100.)\\n\\n\",", + " ((double)(((ulong)1)<<(ssize-10)) / (double) nstates) * 1024.0);", + /* the -10 and *1024 stuff is to avoid overflow */ + " printf(\"bits set per state: %%u (-k%%u)\\n\", hfns, hfns);", + " if (do_hashgen)", + " printf(\"hash polynomial used: 0x%%.8x\\n\", HASH_CONST[HASH_NR]);", + " if (s_rand != 12345)", + " printf(\"random seed used: %%u\\n\", (uint) (s_rand-1));", "#endif", -"#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", + "#if defined(BFS_DISK) && !defined(BFS_PAR)", + " printf(\"bfs disk reads: %%ld writes %%ld -- diff %%ld\\n\",", + " bfs_dsk_reads, bfs_dsk_writes, bfs_dsk_writes-bfs_dsk_reads);", + " if (bfs_dsk_read >= 0) (void) close(bfs_dsk_read);", + " if (bfs_dsk_write >= 0) (void) close(bfs_dsk_write);", + " (void) unlink(\"pan_bfs_dsk.tmp\");", "#endif", "}", + "", "void", "wrapup(void)", - "{", - "#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;", + "{ double nr1, nr2, nr3 = 0.0, nr4, nr5 = 0.0;", + "#ifdef BFS_PAR", + " if (who_am_i != 0)", + " { pan_exit(0);", + " }", "#endif", + "#if NCORE>1", + " if (verbose) cpu_printf(\"wrapup -- %%d error(s)\\n\", errors);", + " if (core_id != 0)", + " {", + " #ifdef USE_DISK", + " void dsk_stats(void);", + " dsk_stats();", + " #endif", + " if (search_terminated != NULL)", + " { *search_terminated |= 2; /* wrapup */", + " }", + " exit(0); /* normal termination, not an error */", + " }", "#endif", - + "#if !defined(WIN32) && !defined(WIN64)", " signal(SIGINT, SIG_DFL);", - " printf(\"(%%s)\\n\", Version);", + "#endif", + " printf(\"\\n(%%s)\\n\", SpinVersion);", " if (!done) printf(\"Warning: Search not completed\\n\");", + "#if defined(BFS_PAR) && !defined(BITSTATE)", + " if (bfs_punt > 0) printf(\"Warning: Search incomplete\\n\");", + "#endif", "#ifdef SC", " (void) unlink((const char *)stackfile);", "#endif", + "#ifdef BFS_PAR", + " printf(\" + Multi-Core (using %%d cores)\\n\", Cores);", + " #ifdef BFS_SEP_HASH", + " printf(\" + Separate Hash Tables\\n\");", + " #endif", + " #ifdef BFS_DISK", + " printf(\" + Disk storage\\n\");", + " #endif", + "#endif", + "#if NCORE>1", + " if (a_cycles)", + " { printf(\" + Multi-Core (NCORE=%%d)\\n\", NCORE);", + " } else", + " { printf(\" + Multi-Core (NCORE=%%d -z%%ld)\\n\", NCORE, z_handoff);", + " }", + "#endif", "#ifdef BFS", - " printf(\" + Using Breadth-First Search\\n\");", + " printf(\" + Breadth-First Search\\n\");", "#endif", "#ifndef NOREDUCE", " printf(\" + Partial Order Reduction\\n\");", "#endif", -#if 0 - "#ifdef Q_PROVISO", - " printf(\" + Queue Proviso\\n\");", + "#ifdef PERMUTED", + " printf(\" + Process Scheduling Permutation\\n\");", + "#endif", + "#ifdef P_REVERSE", + " printf(\" + Reverse Depth-First Search Order\\n\");", + "#endif", + " if (t_reverse)", + " printf(\" + Reverse Transition Ordering\\n\");", + "#ifdef T_RAND", + " printf(\" + Randomized Transition Ordering\\n\");", + "#endif", + "#ifdef P_RAND", + " printf(\" + Randomized Process Ordering\\n\");", + "#endif", + "#ifdef BCS", + " printf(\" + Scheduling Restriction (-L%%d)\\n\", sched_max);", + "#endif", + "#ifdef TRIX", + " printf(\" + Tree Index Compression\\n\");", "#endif", -#endif "#ifdef COLLAPSE", " printf(\" + Compression\\n\");", "#endif", "#ifdef MA", " printf(\" + Graph Encoding (-DMA=%%d)\\n\", MA);", - "#ifdef R_XPT", - " printf(\" Restarted from checkpoint %%s.xpt\\n\", Source);", - "#endif", + " #ifdef R_XPT", + " printf(\" Restarted from checkpoint %%s.xpt\\n\", PanSource);", + " #endif", "#endif", "#ifdef CHECK", - "#ifdef FULLSTACK", + " #ifdef FULLSTACK", " printf(\" + FullStack Matching\\n\");", - "#endif", - "#ifdef CNTRSTACK", + " #endif", + " #ifdef CNTRSTACK", " printf(\" + CntrStack Matching\\n\");", - "#endif", + " #endif", + "#endif", + "#ifdef PERMUTED", + " if (reversing & 2)", + " { if (p_reorder == set_permuted)", + " { printf(\" + Permuted\\n\");", + " }", + " if (p_reorder == set_reversed)", + " { printf(\" + Reversed\\n\");", + " }", + " if (p_reorder == set_rotated)", + " { printf(\" + Rotated %%d\\n\", p_rotate);", + " }", + " if (p_reorder == set_randrot)", + " { printf(\" + RandRotated\\n\");", + " } }", "#endif", "#ifdef BITSTATE", " printf(\"\\nBit statespace search for:\\n\");", "#else", - "#ifdef HC", + " #ifdef HC", " printf(\"\\nHash-Compact %%d search for:\\n\", HC);", - "#else", + " #else", " printf(\"\\nFull statespace search for:\\n\");", - "#endif", + " #endif", "#endif", "#ifdef EVENT_TRACE", "#ifdef NEGATED_TRACE", @@ -2860,7 +4386,8 @@ static char *Code2c[] = { "#endif", "#endif", "#ifdef VERI", - " printf(\"\tnever claim \t+\\n\");", + " printf(\"\tnever claim \t+\");", + " printf(\" (%%s)\\n\", procname[((Pclaim *)pptr(0))->_t]);", " printf(\"\tassertion violations\t\");", " if (noasserts)", " printf(\"- (disabled by -A flag)\\n\");", @@ -2889,7 +4416,11 @@ static char *Code2c[] = { " fairness?\"en\":\"dis\");", " else printf(\"- (not selected)\\n\");", "#else", + " #if !defined(BFS_PAR) || !defined(L_BOUND)", " printf(\"\tcycle checks \t- (disabled by -DSAFETY)\\n\");", + " #else", + " printf(\"\tcycle checks \t+ (bound %%d)\\n\", L_bound);", + " #endif", "#endif", "#ifdef VERI", " printf(\"\tinvalid end states\t- \");", @@ -2905,9 +4436,13 @@ static char *Code2c[] = { " else", " printf(\"+\\n\\n\");", "#endif", - " printf(\"State-vector %%d byte, depth reached %%d\", ", - " hmax, mreached);", + " printf(\"State-vector %%d byte, depth reached %%ld\", hmax,", + "#if NCORE>1", + " (nr_handoffs * z_handoff) +", + "#endif", + " mreached);", " printf(\", errors: %%d\\n\", errors);", + " fflush(stdout);", "#ifdef MA", " if (done)", " { extern void dfa_stats(void);", @@ -2920,124 +4455,196 @@ static char *Code2c[] = { " wrap_stats();", "#ifdef CHECK", " printf(\"stackframes: %%d/%%d\\n\\n\", smax, svmax);", - " printf(\"stats: fa %%d, fh %%d, zh %%d, zn %%d - \",", + " printf(\"stats: fa %%ld, fh %%ld, zh %%ld, zn %%ld - \",", " Fa, Fh, Zh, Zn);", - " printf(\"check %%d holds %%d\\n\", Ccheck, Cholds);", - " printf(\"stack stats: puts %%d, probes %%d, zaps %%d\\n\",", + " printf(\"check %%ld holds %%ld\\n\", Ccheck, Cholds);", + " printf(\"stack stats: puts %%ld, probes %%ld, zaps %%ld\\n\",", " PUT, PROBE, ZAPS);", "#else", " printf(\"\\n\");", "#endif", "", - "#if defined(BITSTATE) || !defined(NOCOMP)", + "#if !defined(BITSTATE) && defined(NOCOMP)", + " if (!verbose) { goto jump_here; }", /* added 5.2.0 */ + "#endif", + "", + "#if 1", /* omitted 5.2.0: defined(BITSTATE) || !defined(NOCOMP) */ " nr1 = (nstates-nShadow)*", - " (double)(hmax+sizeof(struct H_el)-sizeof(unsigned));", - "#ifdef BFS", + " (double)(hmax+sizeof(H_el)-sizeof(unsigned));", + " #ifdef BFS", " nr2 = 0.0;", - "#else", + " #else", " nr2 = (double) ((maxdepth+3)*sizeof(Trail));", - "#endif", + " #endif", - "#ifndef BITSTATE", + " #ifndef BITSTATE", "#if !defined(MA) || defined(COLLAPSE)", - " nr3 = (double) (1L<1 && !defined(SEP_STATE)", + " tmp_nr -= ((double) NCORE * LWQ_SIZE) + GWQ_SIZE;", + " #endif", " if (tmp_nr < 0.0) tmp_nr = 0.;", " printf(\"Stats on memory usage (in Megabytes):\\n\");", - " printf(\"%%-6.3f\tequivalent memory usage for states\",", - " nr1/1000000.);", + " printf(\"%%9.3f\tequivalent memory usage for states\",", + " nr1/1048576.); /* 1024*1024=1048576 */", " printf(\" (stored*(State-vector + overhead))\\n\");", - "#ifdef BITSTATE", -#ifndef POWOW + " #if NCORE>1 && !defined(WIN32) && !defined(WIN64)", + " printf(\"%%9.3f\tshared memory reserved for state storage\\n\",", + " mem_reserved/1048576.);", + " #ifdef SEP_HEAP", + " printf(\"\t\tin %%d local heaps of %%7.3f MB each\\n\",", + " NCORE, mem_reserved/(NCORE*1048576.));", + " #endif", + " printf(\"\\n\");", + " #endif", + " #ifdef BITSTATE", " if (udmem)", - " printf(\"%%-6.3f\tmemory used for hash array (-M%%ld)\\n\",", - " nr3/1000000., udmem/(1024L*1024L));", + " printf(\"%%9.3f\tmemory used for hash array (-M%%ld)\\n\",", + " nr3/1048576., udmem/(1024L*1024L));", " else", -#endif - " printf(\"%%-6.3f\tmemory used for hash array (-w%%d)\\n\",", - " nr3/1000000., ssize);", + " printf(\"%%9.3f\tmemory used for hash array (-w%%d)\\n\",", + " nr3/1048576., ssize);", " if (nr5 > 0.0)", - " printf(\"%%-6.3f\tmemory used for bit stack\\n\",", - " nr5/1000000.);", + " printf(\"%%9.3f\tmemory used for bit stack\\n\",", + " nr5/1048576.);", " 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 \");", - " printf(\"compression: %%.2f%%%%)\\n\",", - " (100.0*tmp_nr)/nr1);", - " } else", - " printf(\"less than 1k)\\n\");", - "#ifndef MA", - " if (tmp_nr > 0.)", - " { printf(\"\tState-vector as stored = %%.0f byte\",", - " (tmp_nr)/(nstates-nShadow) -", - " (double) (sizeof(struct H_el) - sizeof(unsigned)));", - " printf(\" + %%ld byte overhead\\n\",", - " sizeof(struct H_el)-sizeof(unsigned));", + " #else", + " #ifndef USE_TDH", + " printf(\"%%9.3f\tactual memory usage for states\",", + " tmp_nr/1048576.);", + " remainder -= tmp_nr;", + " if (tmp_nr > 0.)", + " { if (tmp_nr < nr1) ", + " { printf(\" (compression: %%.2f%%%%)\\n\",", + " (100.0*tmp_nr)/nr1);", + " } else", + " { printf(\"\\n\");", + " }", + " } else", + " { printf(\" (less than 1k)\\n\");", + " }", + " #ifndef MA", + " if (tmp_nr > 0. && tmp_nr < nr1)", + " { printf(\" \tstate-vector as stored = %%.0f byte\",", + " (tmp_nr)/(nstates-nShadow) -", + " (double) (sizeof(H_el) - sizeof(unsigned)));", + " printf(\" + %%ld byte overhead\\n\",", + " (long int) sizeof(H_el)-sizeof(unsigned));", + " }", + " #endif", + " #endif", + " #if !defined(MA) || defined(COLLAPSE)", + " #ifdef BFS_PAR", + " printf(\"%%9.3f\tshared memory used for hash table (-w%%d)\\n\",", + " ((double) bfs_pre_allocated)/1048576., ssize);", + " #else", + " printf(\"%%9.3f\tmemory used for hash table (-w%%d)\\n\",", + " nr3/1048576., ssize);", + " remainder -= nr3;", + " #endif", + " #endif", + " #endif", + " #ifndef BFS", + " printf(\"%%9.3f\tmemory used for DFS stack (-m%%ld)\\n\",", + " nr2/1048576., maxdepth);", + " remainder -= nr2;", + " #endif", + " #if NCORE>1", + " remainder -= ((double) NCORE * LWQ_SIZE) + GWQ_SIZE;", + " printf(\"%%9.3f\tshared memory used for work-queues\\n\",", + " (GWQ_SIZE + (double) NCORE * LWQ_SIZE) /1048576.);", + " printf(\"\t\tin %%d queues of %%7.3f MB each\",", + " NCORE, (double) LWQ_SIZE /1048576.);", + " #ifndef NGQ", + " printf(\" + a global q of %%7.3f MB\\n\",", + " (double) GWQ_SIZE / 1048576.);", + " #else", + " printf(\"\\n\");", + " #endif", + " #endif", + " if (remainder - fragment > 1048576.)", + " { printf(\"%%9.3f\tother (proc and chan stacks)\\n\",", + " (remainder-fragment)/1048576.);", " }", - "#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", - "#ifndef BFS", - " printf(\"%%-6.3f\tmemory used for DFS stack (-m%%ld)\\n\",", - " nr2/1000000., maxdepth);", - " remainder = remainder - nr2;", - "#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.);", + " if (fragment > 1048576.)", + " { printf(\"%%9.3f\tmemory lost to fragmentation\\n\",", + " fragment/1048576.);", + " }", + " #ifdef BFS_PAR", + " printf(\"%%9.3f\ttotal non-shared memory usage\\n\\n\",", + " memcnt/1048576.);", + " #else", + " printf(\"%%9.3f\ttotal actual memory usage\\n\\n\",", + " memcnt/1048576.);", + " #endif", " }", - "#ifndef MA", + " #ifndef MA", " else", - "#endif", + " #endif", + "#endif", + + "#if !defined(BITSTATE) && defined(NOCOMP)", + "jump_here:", + "#endif", + "#ifndef MA", + " printf(\"%%9.3f\tmemory usage (Mbyte)\\n\",", + " memcnt/1048576.);", + "#endif", + "#ifdef BFS_PAR", + " bfs_report_mem();", + "#else", + " printf(\"\\n\");", "#endif", - "#ifndef MA", - " printf(\"%%-6.3f\tmemory usage (Mbyte)\\n\\n\",", - " memcnt/1000000.);", - "#endif", "#ifdef COLLAPSE", - " printf(\"nr of templates: [ globals chans procs ]\\n\");", + " printf(\"nr of templates: [ 0:globals 1:chans 2:procs ]\\n\");", " printf(\"collapse counts: [ \");", " { int i; for (i = 0; i < 256+2; i++)", " if (ncomps[i] != 0)", - " printf(\"%%d \", ncomps[i]);", + " printf(\"%%d:%%lu \", i, ncomps[i]);", " printf(\"]\\n\");", " }", "#endif", + " #ifdef TRIX", + " if (verbose)", + " { int i;", + " printf(\"TRIX counts:\\n\");", + " printf(\" processes: \");", + " for (i = 0; i < MAXPROC; i++)", + " if (_p_count[i] != 0)", + " { printf(\"%%3d:%%ld \",", + " i, _p_count[i]);", + " }", + " printf(\"\\n channels : \");", + " for (i = 0; i < MAXQ; i++)", + " if (_c_count[i] != 0)", + " { printf(\"%%3d:%%ld \",", + " i, _c_count[i]);", + " }", + " printf(\"\\n\\n\");", + " }", + " #endif", " if ((done || verbose) && !no_rck) do_reach();", "#ifdef PEG", @@ -3053,21 +4660,90 @@ static char *Code2c[] = { "#ifdef SVDUMP", " if (vprefix > 0) close(svfd);", "#endif", + "#ifdef LOOPSTATE", + " printf(\"%%g loopstates hit\\n\", cnt_loops);", + "#endif", + "#ifdef NSUCC", + " dump_succ();", + "#endif", + "#if NCORE>1 && defined(T_ALERT)", + " crash_report();", + "#endif", + "#ifndef BFS_PAR", " pan_exit(0);", + "#endif", "}\n", "void", "stopped(int arg)", - "{ printf(\"Interrupted\\n\");", + "{", + "#ifdef BFS_PAR", + " bfs_shutdown(\"interrupted\");", + "#endif", + " printf(\"Interrupted\\n\");", + "#if NCORE>1", + " was_interrupted = 1;", + "#endif", " wrapup();", " pan_exit(0);", "}", - "/*", - " * based on Bob Jenkins hash-function from 1996", - " * see: http://www.burtleburtle.net/bob/", - " */", "", -"#if defined(HASH64) || defined(WIN64)", - /* 64-bit Jenkins hash: http://burtleburtle.net/bob/c/lookup8.c */ + "/*", + " * super fast hash, based on Paul Hsieh's function", + " * http://www.azillionmonkeys.com/qed/hash.html", + " */", + "#include ", /* for uint32_t etc */ + " #undef get16bits", + " #if defined(__GNUC__) && defined(__i386__)", + " #define get16bits(d) (*((const uint16_t *) (d)))", + " #else", + " #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\\", + " +(uint32_t)(((const uint8_t *)(d))[0]) )", + " #endif", + "", + "void", + "d_sfh(uchar *s, int len)", /* sets one 32-bit number, in K1 */ + "{ uint32_t h = len, tmp;", + " int rem;", + "", + " rem = len & 3;", + " len >>= 2;", + "", + " for ( ; len > 0; len--)", + " { h += get16bits(s);", + " tmp = (get16bits(s+2) << 11) ^ h;", + " h = (h << 16) ^ tmp;", + " s += 2*sizeof(uint16_t);", + " h += h >> 11;", + " }", + " switch (rem) {", + " case 3: h += get16bits(s);", + " h ^= h << 16;", + " h ^= s[sizeof(uint16_t)] << 18;", + " h += h >> 11;", + " break;", + " case 2: h += get16bits(s);", + " h ^= h << 11;", + " h += h >> 17;", + " break;", + " case 1: h += *s;", + " h ^= h << 10;", + " h += h >> 1;", + " break;", + " }", + " h ^= h << 3;", + " h += h >> 5;", + " h ^= h << 4;", + " h += h >> 17;", + " h ^= h << 25;", + " h += h >> 6;", + "", + " K1 = h;", + "}", + "", + "#if WS>4", + "/* 64-bit Jenkins hash, 1997", + " * 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); \\", @@ -3082,66 +4758,242 @@ static char *Code2c[] = { " b -= c; b -= a; b ^= (a<<18); \\", " c -= a; c -= b; c ^= (b>>22); \\", "}", -"#else", + "#else", + "/* 32-bit Jenkins hash, 2006", + " * http://burtleburtle.net/bob/c/lookup3.c", + " */", + "#define rot(x,k) (((x)<<(k))|((x)>>(32-(k))))", + "", "#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); \\", + "{ a -= c; a ^= rot(c, 4); c += b; \\", + " b -= a; b ^= rot(a, 6); a += c; \\", + " c -= b; c ^= rot(b, 8); b += a; \\", + " a -= c; a ^= rot(c,16); c += b; \\", + " b -= a; b ^= rot(a,19); a += c; \\", + " c -= b; c ^= rot(b, 4); b += a; \\", "}", -"#endif", + "", + "#define final(a,b,c) \\", + "{ c ^= b; c -= rot(b,14); \\", + " a ^= c; a -= rot(c,11); \\", + " b ^= a; b -= rot(a,25); \\", + " c ^= b; c -= rot(b,16); \\", + " a ^= c; a -= rot(c,4); \\", + " b ^= a; b -= rot(a,14); \\", + " c ^= b; c -= rot(b,24); \\", + "}", + "#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;", - "", + "d_hash(uchar *kb, int nbytes)", /* sets two 64-bit or 32-bit nrs, depending on WS */ + "{ uint8_t *bp;", + "#if WS>4", + " uint64_t a = 0, b, c, n;", + " const uint64_t *k = (uint64_t *) kb;", + "#else", + " uint32_t a = 0, b, c, n;", + " const uint32_t *k = (uint32_t *) kb;", + "#endif", + " n = nbytes/WS; /* nr of words */", + " /* extend to multiple of words, if needed */", + " a = WS - (nbytes %% WS);", + " if (a > 0 && a < WS)", + " { n++;", + " bp = kb + nbytes;", + " switch (a) {", + "#if WS>4", + " case 7: *bp++ = 0; /* fall thru */", + " case 6: *bp++ = 0; /* fall thru */", + " case 5: *bp++ = 0; /* fall thru */", + " case 4: *bp++ = 0; /* fall thru */", + "#endif", + " case 3: *bp++ = 0; /* fall thru */", + " case 2: *bp++ = 0; /* fall thru */", + " case 1: *bp = 0;", + " case 0: break;", + " } }", + "#if WS>4", " b = HASH_CONST[HASH_NR];", - " while (len >= 3)", + " c = 0x9e3779b97f4a7c13LL; /* arbitrary value */", + " while (n >= 3)", " { a += k[0];", " b += k[1];", " c += k[2];", " mix(a,b,c);", - " k += 3; len -= 3;", + " n -= 3;", + " k += 3;", " }", - " c += length;", - " switch (len) {", + " c += (((uint64_t) nbytes)<<3);", + " switch (n) {", " case 2: b += k[1];", " case 1: a += k[0];", + " case 0: break;", " }", " 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 */ + "#else", /* 32 bit version: */ + " a = c = 0xdeadbeef + (n<<2);", + " b = HASH_CONST[HASH_NR];", + " while (n > 3)", + " { a += k[0];", + " b += k[1];", + " c += k[2];", + " mix(a,b,c);", + " n -= 3;", + " k += 3;", + " }", + " switch (n) { ", + " case 3: c += k[2];", + " case 2: b += k[1];", + " case 1: a += k[0];", + " final(a,b,c);", + " case 0: break;", + " }", + "#endif", + " j1_spin = c&nmask; j3_spin = a&7; /* 1st bit */", + " j2_spin = b&nmask; j4_spin = (a>>3)&7; /* 2nd bit */", + " K1 = c; K2 = b;", "}", + "", + "#if defined(MURMUR) && (WS==8)", + "/* public-domain, 64-bit MurmurHash3, by Austin Appleby */", + "/* https://code.google.com/p/smhasher/wiki/MurmurHash3 */", "void", - "s_hash(uchar *cp, int om)", - "{ d_hash(cp, om); /* sets K1 and K2 */", + "m_hash(uchar *v, int len)", + "{ uint8_t *bp, *data = (uint8_t*) v;", + " int i, nblocks = len / 16;", + "", + " uint64_t h1 = HASH_CONST[HASH_NR];", + " uint64_t h2 = 0x9e3779b97f4a7c13LL;", + "", + " uint64_t c1 = 0x87c37b91114253d5;", + " uint64_t c2 = 0x4cf5ad432745937f;", + "", + " uint64_t *blocks = (uint64_t *)(data);", + "", + " /* guarantee a multiple of 16 bytes */", + " i = 16 - (len %% 16);", + " if (i > 0 && i < 16)", + " { nblocks++;", + " bp = v + len;", + " switch (i) {", + " case 15: *bp++ = 0; /* fall thru */", + " case 14: *bp++ = 0;", + " case 13: *bp++ = 0;", + " case 12: *bp++ = 0;", + " case 11: *bp++ = 0;", + " case 10: *bp++ = 0;", + " case 9: *bp++ = 0;", + " case 8: *bp++ = 0;", + " case 7: *bp++ = 0;", + " case 6: *bp++ = 0;", + " case 5: *bp++ = 0;", + " case 4: *bp++ = 0;", + " case 3: *bp++ = 0;", + " case 2: *bp++ = 0;", + " case 1: *bp = 0;", + " case 0: break;", + " } }", + "", + " for (i = 0; i < nblocks; i++)", + " { uint64_t k1 = blocks[i*2];", + " uint64_t k2 = blocks[i*2+1];", + "", + " k1 *= c1;", + " k1 = (k1 << 31) | (k1 >> 33);", + " k1 *= c2;", + " h1 ^= k1;", + "", + " h1 = (h1 << 27) | (h1 >> 37);", + " h1 += h2;", + " h1 = h1 * 5 + 0x52dce729;", + "", + " k2 *= c2;", + " k2 = (k2 << 33) | (k2 >> 31);", + " k2 *= c1;", + " h2 ^= k2;", + "", + " h2 = (h2 << 31) | (h2 >> 33);", + " h2 += h1;", + " h2 = h2 * 5 + 0x38495ab5;", + " }", + "", + " uint8_t *tail = (uint8_t*)(data + (nblocks * 16));", + "", + " uint64_t k1 = 0;", + " uint64_t k2 = 0;", + "", + " switch(len & 15) {", + " case 15: k2 ^= ((uint64_t) tail[14]) << 48; break;", + " case 14: k2 ^= ((uint64_t) tail[13]) << 40; break;", + " case 13: k2 ^= ((uint64_t) tail[12]) << 32; break;", + " case 12: k2 ^= ((uint64_t) tail[11]) << 24; break;", + " case 11: k2 ^= ((uint64_t) tail[10]) << 16; break;", + " case 10: k2 ^= ((uint64_t) tail[ 9]) << 8; break;", + " case 9: k2 ^= ((uint64_t) tail[ 8]) << 0; break;", + " k2 *= c2;", + " k2 = (k2 << 33) | (k2 >> 31);", + " k2 *= c1;", + " h2 ^= k2; break;", + " case 8: k1 ^= ((uint64_t) tail[7]) << 56; break;", + " case 7: k1 ^= ((uint64_t) tail[6]) << 48; break;", + " case 6: k1 ^= ((uint64_t) tail[5]) << 40; break;", + " case 5: k1 ^= ((uint64_t) tail[4]) << 32; break;", + " case 4: k1 ^= ((uint64_t) tail[3]) << 24; break;", + " case 3: k1 ^= ((uint64_t) tail[2]) << 16; break;", + " case 2: k1 ^= ((uint64_t) tail[1]) << 8; break;", + " case 1: k1 ^= ((uint64_t) tail[0]) << 0; break;", + " k1 *= c1;", + " k1 = (k1 << 31) | (k1 >> 33);", + " k1 *= c2;", + " h1 ^= k1;", + " };", + "", + " h1 ^= len; h2 ^= len;", + " h1 += h2;", + " h2 += h1;", + " h1 ^= h1 >> 33;", + " h1 *= 0xff51afd7ed558ccd;", + " h1 ^= h1 >> 33;", + " h1 *= 0xc4ceb9fe1a85ec53;", + " h1 ^= h1 >> 33;", + " h2 ^= h2 >> 33;", + " h2 *= 0xff51afd7ed558ccd;", + " h2 ^= h2 >> 33;", + " h2 *= 0xc4ceb9fe1a85ec53;", + " h2 ^= h2 >> 33;", + " h1 += h2;", + " h2 += h1;", + "", + " j1_spin = h1&nmask; j3_spin = (h1>>48)&7;", + " j2_spin = h2&nmask; j4_spin = (h2>>48)&7;", + " K1 = h1; K2 = h2;", + "}", + "#endif", + "", + "void", + "s_hash(uchar *cp, int om)", /* uses either d_sfh (1x32bit), or d_hash (2x64bit) */ + "{", /* depending on ssize ie the -w parameter */ + " hasher(cp, om); /* sets K1 */", "#ifdef BITSTATE", " if (S_Tab == H_tab)", /* state stack in bitstate search */ - " j1 = K1 %% omaxdepth;", + " j1_spin = K1 %% omaxdepth;", " else", - "#endif", /* if (S_Tab != H_Tab) */ - " if (ssize < 8*WS)", - " j1 = K1&mask;", - " else", - " j1 = K1;", + "#endif", + " if (ssize < 8*WS)", + " j1_spin = K1&mask;", + " else", + " j1_spin = K1;", "}", "#ifndef RANDSTOR", "int *prerand;", "void", "inirand(void)", "{ int i;", - " srand(123); /* fixed startpoint */", + " srand(s_rand+HASH_NR);", /* inirand */ " prerand = (int *) emalloc((omaxdepth+3)*sizeof(int));", " for (i = 0; i < omaxdepth+3; i++)", - " prerand[i] = rand();", + " { prerand[i] = rand();", + " }", "}", "int", "pan_rand(void)", @@ -3150,28 +5002,271 @@ static char *Code2c[] = { "}", "#endif", "", + "void", + "set_masks(void)", + "{", + " if (WS == 4 && ssize >= 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 = ((ONE_L<>3;", + "#else", + " nmask = mask;", + "#endif", + " } else if (WS != 4)", + " { fprintf(stderr, \"pan: wordsize %%ld not supported\\n\", (long int) WS);", + " exit(1);", + " } else /* WS == 4 and ssize < 32 */", + " { mask = ((ONE_L<>3);", + " }", + "}", + "", + "#if defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(MA)", + "#if NCORE>1", + " #error cannot combine AUTO_RESIZE with NCORE>1", + "#endif", + "static long reclaim_size;", + "static char *reclaim_mem;", + "static H_el **N_tab;", + "void", + "reverse_capture(H_el *p)", + "{ if (!p) return;", + " reverse_capture(p->nxt);", + " /* last element of list moves first */", + " /* to preserve list-order */", + " j2_spin = p->m_K1;", + " if (ssize < 8*WS) /* probably always true */", + " { j2_spin &= mask;", + " }", + " p->nxt = N_tab[j2_spin];", + " N_tab[j2_spin] = p;", + "}", + "void", + "resize_hashtable(void)", + "{", + "#ifndef BFS_PAR", /* ssize and mask/nmask are not in shared mem */ + " if (WS == 4 && ssize >= 27 - 1)", + "#endif", + " { return; /* cannot increase further */", + " }", + "", + " ssize += 2; /* 4x size @htable ssize */", + "", + " printf(\"pan: resizing hashtable to -w%%d.. \", ssize);", + "", + " N_tab = (H_el **) emalloc((ONE_L<1", + "int", + "find_claim(char *s)", + "{ int i, j;", + " for (i = 0; strncmp(procname[i], \":np_:\", 5) != 0; i++)", + " { if (strcmp(s, procname[i]) == 0)", + " { for (j = 0; j < NCLAIMS; j++)", + " { if (spin_c_typ[j] == i)", + " { return j;", + " } }", + " break;", + " } }", + " printf(\"pan: error: cannot find claim '%%s'\\n\", s);", + " exit(1);", + " return -1; /* unreachable */", + "}", + "#endif", + "", + "#if defined(BFS_PAR) && defined(BFS_SEP_HASH)", + "int /* to avoid having to include and compile with -lm */", + "blog2(int n) /* n >= 1 */", + "{ int m=1, r=2;", + " if (n == 1) { return 0; }", + " if (n == 2) { return 1; }", + " while (n > r) { m++; r *= 2; }", + " return m;", + "}", + "#endif", + "", + "uint pp[33];", + "", + "uint ", + "mul(uint a, uint b, uint p)", + "{ int c = 0;", + " while (a)", + " { if (a&1)", + " { a ^= 1;", + " c ^= b;", + " }", + " a = (a>>1);", + " if (b & 0x80000000)", + " { b += b;", + " b ^= p;", + " } else", + " { b += b;", + " } }", + " return c;", + "}", + "", + "uint", + "ppow(int n, uint p)", + "{ uint t = 1; int i;", + " for (i = 0; i < 32; i++)", + " { if (n & (1<0)", + " s_rand = T_RAND;", /* so that -RS can override */ + "#elif defined(P_RAND) && (P_RAND>0)", + " s_rand = P_RAND;", + "#endif", + "", + "#ifdef PUTPID", + " { char *ptr = strrchr(argv[0], '/');", + " if (ptr == NULL)", + " { ptr = argv[0];", + " } else", + " { ptr++;", + " }", + " progname = emalloc(strlen(ptr));", + " strcpy(progname, ptr);", + " /* printf(\"progname: %%s\\n\", progname); */", + " }", + "#endif", + "", "#ifdef BITSTATE", - " bstore = bstore_reg; /* default */", + " b_store = bstore_reg; /* default */", + "#endif", + "#if NCORE>1", + " { int i, j;", + " strcpy(o_cmdline, \"\");", + " for (j = 1; j < argc; j++)", + " { strcat(o_cmdline, argv[j]);", + " strcat(o_cmdline, \" \");", + " }", + " /* printf(\"Command Line: %%s\\n\", o_cmdline); */", + " if (strlen(o_cmdline) >= sizeof(o_cmdline))", + " { Uerror(\"option list too long\");", + " } }", "#endif", " while (argc > 1 && argv[1][0] == '-')", " { switch (argv[1][1]) {", "#ifndef SAFETY", - "#ifdef NP", - " case 'a': fprintf(efd, \"error: -a disabled\");", - " usage(efd); break;", - "#else", + " #ifdef NP", + " case 'a': fprintf(efd, \"warning: -a is disabled by -DNP, ignored\");", + " break;", + " #else", " case 'a': a_cycles = 1; break;", - "#endif", + " #endif", + "#else", + " #if defined(BFS_PAR) && defined(L_BOUND)", + " case 'a': if (isdigit(argv[1][2]))", + " { L_bound = atoi(&argv[1][2]);", + " if (L_bound < 1 || L_bound > 255)", + " { printf(\"usage: -aN with 00", + " case 'C': coltrace = 1; goto samething;", + " #endif", + "#endif", + " case 'c': upto = atoi(&argv[1][2]); break;", + " case 'D': dodot++; state_tables++; break;", " case 'd': state_tables++; break;", - " case 'e': every_error = 1; Nr_Trails = 1; break;", + " case 'e': every_error = 1; upto = 0; Nr_Trails = 1; break;", " case 'E': noends = 1; break;", "#ifdef SC", " case 'F': if (strlen(argv[1]) > 2)", @@ -3181,23 +5276,57 @@ static char *Code2c[] = { "#if !defined(SAFETY) && !defined(NOFAIR)", " case 'f': fairness = 1; break;", "#endif", - " case 'h': if (!argv[1][2]) usage(efd); else", - " HASH_NR = atoi(&argv[1][2])%%33; break;", + "#ifdef HAS_CODE", + " #if HAS_CODE>0", + " case 'g': gui = 1; goto samething;", + " #endif", + "#endif", + " case 'h':", + " if (strncmp(&argv[1][1], \"hash\", strlen(\"hash\")) == 0)", + " { do_hashgen = 1;", + " break;", + " }", + " if (!argv[1][2] || !isdigit((int) argv[1][2]))", + " { usage(efd); /* exits */", + " }", + " HASH_NR = atoi(&argv[1][2])%%(sizeof(HASH_CONST)/sizeof(uint));", + " break;", " case 'I': iterative = 2; every_error = 1; break;", - " case 'i': iterative = 1; every_error = 1; break;", + " case 'i':", + " if (strncmp(&argv[1][1], \"i_reverse\", strlen(\"i_reverse\")) == 0)", + " { reversing |= 1;", + " } else", + " { 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", + "#ifdef BCS", + " case 'L':", + " sched_max = atoi(&argv[1][2]);", + " if (sched_max > 255) /* stored as one byte */", + " { fprintf(efd, \"warning: using max bound (255)\\n\");", + " sched_max = 255;", + " }", + " #ifndef NOREDUCE", + " if (sched_max == 0)", + " { fprintf(efd, \"warning: with (default) bound -L0, \");", + " fprintf(efd, \"using -DNOREDUCE performs better\\n\");", + " }", + " #endif", + " break;", + "#endif", "#ifndef SAFETY", "#ifdef NP", " case 'l': a_cycles = 1; break;", "#else", - " case 'l': fprintf(efd, \"error: -l disabled\");", + " case 'l': fprintf(efd, \"error: -l not available (compile with -DNP)\");", " 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;", @@ -3206,66 +5335,344 @@ static char *Code2c[] = { " fprintf(stderr, \"-M and -G affect only -DBITSTATE\\n\");", " break;", "#endif", -#endif " case 'm': maxdepth = atoi(&argv[1][2]); break;", + "#ifndef NOCLAIM", + " case 'N':", + " #if NCLAIMS>1", + " if (isdigit((int)argv[1][2]))", + " { whichclaim = atoi(&argv[1][2]);", + " } else if (isalpha((int)argv[1][2]))", + " { claimname = &argv[1][2];", + " } else if (argc > 2 && argv[2][0] != '-') /* check next arg */", + " { claimname = argv[2];", + " argc--; argv++; /* skip next arg */", + " }", + " #else", + " #if NCLAIMS==1", + " fprintf(stderr, \"warning: only one claim defined, -N ignored\\n\");", + " #else", + " fprintf(stderr, \"warning: no claims defined, -N ignored\\n\");", + " #endif", + " if (!isdigit((int)argv[1][2]) && argc > 2 && argv[2][0] != '-')", + " { argc--; argv++;", + " }", + " #endif", + "#endif", + " break;\n", " case 'n': no_rck = 1; break;", + "", + " case 'P':", + " if (!readtrail", + " && isdigit((int) argv[1][2]))", /* was argv[1][2] == '_' */ + " { int x = atoi(&argv[1][2]);", + " if (x != 0 && x != 1)", + " { fprintf(efd, \"pan: bad option -P[01], ignored\\n\");", + " }", + " if (x == 0)", + " { reversing &= ~1;", + " break;", + " }", + " if (x == 1)", + " { reversing |= 1;", + " break;", + " }", + " if (verbose)", + " fprintf(efd, \"pan: reversed *active* process creation %%s\\n\",", + " reversing&1?\"on\":\"off\");", + " break;", + " } /* else */", + "#ifdef HAS_CODE", + " #if HAS_CODE>0", + " readtrail = 1; onlyproc = atoi(&argv[1][2]);", + " if (argc > 2 && argv[2][0] != '-') /* check next arg */", + " { trailfilename = argv[2];", + " argc--; argv++; /* skip next arg */", + " }", + " #else", + " fprintf(efd, \"pan: option -P not recognized, ignored\\n\");", + " #endif", + "#else", + " fprintf(efd, \"pan: option -P not recognized, ignored\\n\");", + "#endif", + " break;", + "", + " case 'p':", + " #if !defined(BFS) && !defined(BFS_PAR)", + " #ifdef PERMUTED", + " if (strncmp(&argv[1][1], \"p_normal\", strlen(\"p_normal\")) == 0)", + " { reversing &= ~2;", + " break;", + " }", + " reversing |=2;", + " if (strncmp(&argv[1][1], \"p_permute\", strlen(\"p_permute\")) == 0)", + " { p_reorder = set_permuted;", + " break;", + " }", + " if (strncmp(&argv[1][1], \"p_rotate\", strlen(\"p_rotate\")) == 0)", + " { p_reorder = set_rotated;", + " if (isdigit((int) argv[1][9]))", + " { p_rotate = atoi(&argv[1][9]);", + " } else", + " { p_rotate = 1;", + " }", + " break;", + " }", + " if (strncmp(&argv[1][1], \"p_randrot\", strlen(\"p_randrot\")) == 0)", + " { p_reorder = set_randrot;", + " break;", + " }", + " if (strncmp(&argv[1][1], \"p_reverse\", strlen(\"p_reverse\")) == 0)", + " { p_reorder = set_reversed;", + " break;", + " }", + " #else", + " if (strncmp(&argv[1][1], \"p_permute\", strlen(\"p_permute\")) == 0", + " || strncmp(&argv[1][1], \"p_rotate\", strlen(\"p_rotate\")) == 0", + " || strncmp(&argv[1][1], \"p_randrot\", strlen(\"p_randrot\")) == 0", + " || strncmp(&argv[1][1], \"p_reverse\", strlen(\"p_reverse\")) == 0)", + " { fprintf(efd, \"option %%s required compilation with -DPERMUTED\\n\",", + " argv[1]);", + " exit(1);", + " }", + " #endif", + " #endif", "#ifdef SVDUMP", - " case 'p': vprefix = atoi(&argv[1][2]); break;", + " vprefix = atoi(&argv[1][2]);", + "#else", + " fprintf(efd, \"invalid option '%%s' -- ignored\\n\", argv[1]);", + "#endif", + " break;", + "#if NCORE==1", + " case 'Q': quota = (double) 60.0 * (double) atoi(&argv[1][2]);", + " #ifndef FREQ", + " freq /= 10.; /* for better resolution */", + " #endif", + " 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;", - " case 'S': silent = 1; break;", - "#endif", - " case 'R': Nrun = atoi(&argv[1][2]); break;", + " case 'R':", + " if (argv[1][2] == 'S') /* e.g., -RS76842 */", + " { s_rand = atoi(&argv[1][3]);", /* RS */ + " break;", + " }", "#ifdef BITSTATE", - " case 's': hfns = 1; break;", + " Nrun = atoi(&argv[1][2]);", + " if (Nrun > 100)", + " { Nrun = 100;", + " } else if (Nrun < 1)", + " { Nrun = 1;", + " }", + "#else", + " usage(efd);", + " 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(); pan_exit(0); break;", - " case 'v': verbose = 1; break;", - " case 'w': ssize = atoi(&argv[1][2]); break;", + " case 'r':", + " if (strncmp(&argv[1][1], \"rhash\", strlen(\"rhash\")) == 0)", + " { if (s_rand == 12345) /* default seed */", + " {", + "#if defined(WIN32) || defined(WIN64)", + " s_rand = (uint) clock();", + "#else", + " struct tms dummy_tm;", + " s_rand = (uint) times(&dummy_tm);", + "#endif", + " }", + " srand(s_rand++);", + " #ifdef PERMUTED", + " do_hashgen = 1;", /* + randomize p_rotate, p_reverse, p_permute */ + " switch (rand()%%5) {", + " case 0: p_reorder = set_permuted;", + " reversing |=2;", + " break;", + " case 1: p_reorder = set_reversed;", + " reversing |=2;", + " break;", + " /* fully randomize p_rotate: */", + " case 2: p_reorder = set_randrot;", + " reversing |=2;", + " break;", + " /* choose once, then keep p_rotate fixed: */", + " case 3: p_reorder = set_rotated;", + " p_rotate = rand()%%3;", + " reversing |=2;", + " break;", + " default: /* standard search */ break;", + " }", + " if (rand()%%2 == 0)", + " { t_reverse = 1;", + " }", + " break;", + " #else", + " fprintf(efd, \"option -rhash requires compilation with -DPERMUTED\\n\");", + " exit(1);", + " #endif", + " }", + "#if defined(HAS_CODE) && HAS_CODE>0", + "samething: readtrail = 1;", + " if (isdigit((int)argv[1][2]))", + " whichtrail = atoi(&argv[1][2]);", + " else if (argc > 2 && argv[2][0] != '-') /* check next arg */", + " { trailfilename = argv[2];", + " argc--; argv++; /* skip next arg */", + " }", + " break;", + " case 'S': silent = 1; goto samething;", + "#else", + " fprintf(efd, \"options -r is for models with embedded C code\\n\");", + " break;", + "#endif", + " case 'T':", + " if (isdigit((int) argv[1][2]))", /* was argv[1][2] == '_' */ + " { t_reverse = atoi(&argv[1][2]);", + " if (verbose)", + " printf(\"pan: reverse transition ordering %%s\\n\",", + " t_reverse?\"on\":\"off\");", + " break;", + " }", + " TMODE = 0444;", + " break;", + " case 't':", + " if (strncmp(&argv[1][1], \"t_reverse\", strlen(\"t_reverse\")) == 0)", + " { t_reverse = 1;", + " break;", + " }", /* i.e., a trail prefix cannot be '_reverse' */ + " if (argv[1][2])", + " { tprefix = &argv[1][2];", + " }", + " break;", + " case 'u':", + " #ifdef BFS_PAR", + " ncores = atoi(&argv[1][2]);", + " #endif", + " break;", + " case 'V': start_timer(); printf(\"Generated by %%s\\n\", SpinVersion);", + " to_compile(); pan_exit(2); break;", + " case 'v': verbose++; break;", + " case 'w': ssize = atoi(&argv[1][2]);", + " #if defined(BFS_PAR) && defined(BFS_SEP_HASH)", + " used_w = 1;", + " #endif", + " break;", " case 'Y': signoff = 1; break;", " case 'X': efd = stdout; break;", - " default : fprintf(efd, \"saw option -%%c\\n\", argv[1][1]); usage(efd); break;", + " case 'x': exclusive = 1; break;", + " #if NCORE>1", + " /* -B ip is passthru to proxy of remote ip address: */", + " case 'B': argc--; argv++; break;", + " case 'Q': worker_pids[0] = atoi(&argv[1][2]); break;", + " /* -Un means that the nth worker should be instantiated as a proxy */", + " case 'U': proxy_pid = atoi(&argv[1][2]); break;", + " /* -W means this copy is started by a cluster-server as a remote */", + " /* this flag is passed to ./pan_proxy, which interprets it */", + " case 'W': remote_party++; break;", + " case 'Z': core_id = atoi(&argv[1][2]);", + " if (verbose)", + " { printf(\"cpu%%d: pid %%d parent %%d\\n\",", + " core_id, getpid(), worker_pids[0]);", + " }", + " break;", + " case 'z': z_handoff = atoi(&argv[1][2]); break;", + " #else", + " case 'z': break; /* ignored for single-core */", + " #endif", + " default : fprintf(efd, \"saw option -%%c\\n\",", + " argv[1][1]); usage(efd); break;", " }", " argc--; argv++;", " }", + "#if defined(BFS_PAR) && defined(BFS_SEP_HASH)", + " if (used_w == 0)", + " { if (ncores == 0) /* all cores used, by default */", + " { ssize -= blog2(BFS_MAXPROCS - 1);", + " } else", + " { ssize -= blog2(ncores);", + " } }", + "#endif", + " if (do_hashgen)", + " { hashgen();", /* placed here so that -RSn can appear after -hash */ + " }", + "#ifndef SAFETY", + " if (fairness && !a_cycles)", + " { fprintf(efd, \"error: -f requires the use of -a or -l\\n\");", + " usage(efd);", + " }", + " #if ACCEPT_LAB==0", + " if (a_cycles)", + " { fprintf(efd, \"warning: no accept labels are defined, \");", + " fprintf(efd, \"so option -a has no effect (ignored)\\n\");", + " a_cycles = 0;", + " }", + " #endif", + "#endif", + "", + "#ifdef BFS_PAR", + " uerror = bfs_uerror;", + " Uerror = bfs_Uerror;", + "#else", + " uerror = dfs_uerror;", + " Uerror = dfs_Uerror;", + "#endif", + " if (ssize <= 32) /* 6.2.0 */", + " { hasher = d_sfh;", + "#if !defined(BITSTATE) && defined(USE_TDH)", + " o_hash = o_hash32;", + "#endif", + " } else", + " { hasher = d_hash;", + "#if !defined(BITSTATE) && defined(USE_TDH)", + " o_hash = o_hash64;", + "#endif", + " }", " if (iterative && TMODE != 0666)", " { TMODE = 0666;", " fprintf(efd, \"warning: -T ignored when -i or -I is used\\n\");", " }", "#if defined(WIN32) || defined(WIN64)", + " #ifndef _S_IWRITE", + " #define S_IWRITE 0000200 /* write permission, owner */", + " #endif", + " #ifndef _S_IREAD", + " #define S_IREAD 0000400 /* read permission, owner */", + " #endif", " if (TMODE == 0666)", - " TMODE = _S_IWRITE | _S_IREAD;", + " TMODE = S_IWRITE | S_IREAD;", " else", - " TMODE = _S_IREAD;", + " TMODE = S_IREAD;", "#endif", - "#ifdef OHASH", - " fprintf(efd, \"warning: -DOHASH no longer supported (directive ignored)\\n\");", + "#if NCORE>1", + " store_proxy_pid = proxy_pid; /* for checks in mem_file() and someone_crashed() */", + " if (core_id != 0) { proxy_pid = 0; }", + " #ifndef SEP_STATE", + " if (core_id == 0 && a_cycles)", + " { fprintf(efd, \"hint: this search may be more efficient \");", + " fprintf(efd, \"if pan.c is compiled -DSEP_STATE\\n\");", + " }", + " #endif", + " if (z_handoff < 0)", + " { z_handoff = 20; /* conservative default - for non-liveness checks */", + " }", + "#if defined(NGQ) || defined(LWQ_FIXED)", + " LWQ_SIZE = (double) (128.*1048576.);", + "#else", + " LWQ_SIZE = (double) ( z_handoff + 2.) * (double) sizeof(SM_frame);", + /* the added margin of +2 is not really necessary */ "#endif", - "#ifdef JHASH", - " fprintf(efd, \"warning: -DJHASH no longer supported (directive ignored)\\n\");", + " #if NCORE>2", + " if (a_cycles)", + " { fprintf(efd, \"warning: the intended nr of cores to be used in liveness mode is 2\\n\");", + " #ifndef SEP_STATE", + " fprintf(efd, \"warning: without -DSEP_STATE there is no guarantee that all liveness violations are found\\n\");", + " #endif", + " }", /* it still works though, the later cores get states from the global q */ + " #endif", + " #ifdef HAS_HIDDEN", + " #error cannot use hidden variables when compiling multi-core", + " #endif", "#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\");", + "#if defined(T_RAND) && defined(ELSE_IN_GUARD)", + " #error cannot hide 'else' as guard in d_step, when using -DT_RAND", "#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);", @@ -3278,7 +5685,7 @@ static char *Code2c[] = { " 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", + " * power of 2 that can be represented in an ulong", " */", " }", "#else", @@ -3297,8 +5704,8 @@ static char *Code2c[] = { " hiwater = HHH = maxdepth-10;", " DDD = HHH/2;", " if (!stackfile)", - " { stackfile = (char *) emalloc(strlen(Source)+4+1);", - " sprintf(stackfile, \"%%s._s_\", Source);", + " { stackfile = (char *) emalloc(strlen(PanSource)+4+1);", + " sprintf(stackfile, \"%%s._s_\", PanSource);", " }", " if (iterative)", " { fprintf(efd, \"error: cannot use -i or -I with -DSC\\n\");", @@ -3307,69 +5714,97 @@ static char *Code2c[] = { "#endif", "#if (defined(R_XPT) || defined(W_XPT)) && !defined(MA)", - " fprintf(efd, \"error: -D?_XPT requires -DMA\\n\");", - " exit(1);", + " #warning -DR_XPT and -DW_XPT assume -DMA (ignored)", "#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);", + " #ifdef SC", + " #error -DBFS not compatible with -DSC", + " #endif", + " #ifdef HAS_LAST", + " #error -DBFS not compatible with _last", + " #endif", + " #ifdef HAS_STACK", + " #error cannot use c_track UnMatched with BFS", + " #endif", + " #ifdef BCS", + " #error -DBFS not compatible with -DBCS", + " #endif", + " #ifdef REACH", + " #warning -DREACH is redundant when -DBFS is used", + " #endif", "#endif", - "#if defined(HAS_LAST)", - " fprintf(efd, \"error: -DBFS not compatible with _last\\n\");", - " exit(1);", + + "#ifdef TRIX", + " #ifdef BITSTATE", + " #error cannot combine -DTRIX and -DBITSTATE", + " #endif", + " #ifdef COLLAPSE", + " #error cannot combine -DTRIX and -DCOLLAPSE", + " #endif", + " #ifdef MA", + " #error cannot combine -DTRIX and -DMA", + " #endif", + " #if defined(BFS_PAR) && defined(BFS_SEP_HEAP)", + " #error cannot combined -DBFS_SEP_HEAP with -DTRIX", + " #endif", "#endif", - "#if defined(REACH)", - " fprintf(efd, \"warning: -DREACH redundant when -DBFS is used\\n\");", + + "#ifdef BFS_PAR", + " #ifdef NP", + " #error cannot combine -DBFS_PAR and -DNP", + " #undef NP", + " #endif", "#endif", - "#if defined(HAS_STACK)", - " fprintf(efd, \"error: cannot use UnMatched qualifier on c_track with BFS\\n\");", - " exit(1);", + + "#ifdef NOCLAIM", + " #ifdef NP", + " #warning using -DNP overrides -DNOCLAIM", + " #undef NOCLAIM", + " #endif", "#endif", + + "#ifdef BCS", + " #ifdef P_RAND", + " #error cannot combine -DBCS and -DP_RAND", + " #endif", + " #ifdef BFS", + " #error cannot combine -DBCS and -DBFS", + " #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\");", - " pan_exit(1);", + " #error to use -DPEG use: spin -o3 -a", "#endif", - "#ifdef HC", - "#ifdef NOCOMP", - " fprintf(efd, \"error: cannot combine -DHC and -DNOCOMP\\n\");", - " pan_exit(1);", - "#endif", - "#ifdef BITSTATE", - " fprintf(efd, \"error: cannot combine -DHC and -DBITSTATE\\n\");", - " pan_exit(1);", - "#endif", + "#if defined(HC) && !defined(BFS_PAR)", + " #ifdef NOCOMP", + " #error cannot combine -DHC and -DNOCOMP", + " #endif", + " #ifdef BITSTATE", + " #error cannot combine -DHC and -DBITSTATE", + " #endif", "#endif", "#if defined(SAFETY) && defined(NP)", - " fprintf(efd, \"error: cannot combine -DNP and -DSAFETY\\n\");", - " pan_exit(1);", + " #error cannot combine -DNP and -DBFS or -DSAFETY", "#endif", "#ifdef MA", - "#ifdef BITSTATE", - " fprintf(efd, \"error: cannot combine -DMA and -DBITSTATE\\n\");", - " pan_exit(1);", - "#endif", - " if (MA <= 0)", - " { fprintf(efd, \"usage: -DMA=N with N > 0 and < VECTORSZ\\n\");", - " pan_exit(1);", - " }", + " #ifdef BITSTATE", + " #error cannot combine -DMA and -DBITSTATE", + " #endif", + " #if MA <= 0", + " #error usage: -DMA=N with N > 0 and N < VECTORSZ", + " #endif", "#endif", "#ifdef COLLAPSE", - "#if defined(BITSTATE)", - " fprintf(efd, \"error: cannot combine -DBITSTATE and -DCOLLAPSE\\n\");", - " pan_exit(1);", - "#endif", - "#if defined(NOCOMP)", - " fprintf(efd, \"error: cannot combine -DNOCOMP and -DCOLLAPSE\\n\");", - " pan_exit(1);", - "#endif", + " #ifdef BITSTATE", + " #error cannot combine -DBITSTATE and -DCOLLAPSE", + " #endif", + " #ifdef NOCOMP", + " #error cannot combine -DCOLLAPSE and -DNOCOMP", + " #endif", "#endif", " if (maxdepth <= 0 || ssize <= 1) usage(efd);", "#if SYNC>0 && !defined(NOREDUCE)", @@ -3382,202 +5817,147 @@ static char *Code2c[] = { " }", "#endif", "#if defined(REM_VARS) && !defined(NOREDUCE)", - " { fprintf(efd, \"warning: p.o. reduction not compatible with \");", - " fprintf(efd, \"remote varrefs (use -DNOREDUCE)\\n\");", - " }", + " #warning p.o. reduction not compatible with remote varrefs (use -DNOREDUCE)", "#endif", "#if defined(NOCOMP) && !defined(BITSTATE)", " if (a_cycles)", - " { fprintf(efd, \"error: -DNOCOMP voids -l and -a\\n\");", + " { fprintf(efd, \"error: use of -DNOCOMP voids -l and -a\\n\");", " pan_exit(1);", " }", "#endif", - - "#ifdef MEMLIM", /* MEMLIM setting takes precedence */ - " memlim = (double) MEMLIM * (double) (1<<20); /* size in Mbyte */", - "#else", - "#ifdef MEMCNT", - "#if MEMCNT<31", - " memlim = (double) (1< 1) HASH_NR = Nrun - 1;", + "#if SYNC>0", + " #ifdef HAS_PRIORITY", + " #error use of priorities cannot be combined with rendezvous", + " #elif HAS_ENABLED", + " #error use of enabled() cannot be combined with rendezvous", + " #endif", "#endif", - " if (Nrun < 1 || Nrun > 32)", - " { fprintf(efd, \"error: invalid arg for -R\\n\");", - " usage(efd);", - " }", - "#ifndef SAFETY", - " if (fairness && !a_cycles)", - " { fprintf(efd, \"error: -f requires -a or -l\\n\");", - " usage(efd);", - " }", - "#if ACCEPT_LAB==0", - " if (a_cycles)", - "#ifndef VERI", - " { fprintf(efd, \"error: no accept labels defined \");", - " fprintf(efd, \"in model (for option -a)\\n\");", - " usage(efd);", - " }", - "#else", - " { fprintf(efd, \"warning: no explicit accept labels \");", - " fprintf(efd, \"defined in model (for -a)\\n\");", - " }", - "#endif", - "#endif", - "#endif", - "#if !defined(NOREDUCE)", - "#if defined(HAS_ENABLED)", - " fprintf(efd, \"error: reduced search precludes \");", - " fprintf(efd, \"use of 'enabled()'\\n\");", - " pan_exit(1);", - "#endif", - "#if defined(HAS_PCVALUE)", - " fprintf(efd, \"error: reduced search precludes \");", - " fprintf(efd, \"use of 'pcvalue()'\\n\");", - " pan_exit(1);", - "#endif", - "#if defined(HAS_BADELSE)", - " fprintf(efd, \"error: reduced search precludes \");", - " fprintf(efd, \"using 'else' combined with i/o stmnts\\n\");", - " pan_exit(1);", - "#endif", - "#if defined(HAS_LAST)", - " fprintf(efd, \"error: reduced search precludes \");", - " fprintf(efd, \"use of _last\\n\");", - " pan_exit(1);", - "#endif", + "#ifndef NOREDUCE", + " #ifdef HAS_PRIORITY", + " #warning use of priorities requires -DNOREDUCE", + " #elif HAS_ENABLED", + " #error use of enabled() requires -DNOREDUCE", + " #endif", + " #ifdef HAS_PCVALUE", + " #error use of pcvalue() requires -DNOREDUCE", + " #endif", + " #ifdef HAS_BADELSE", + " #error use of 'else' combined with i/o stmnts requires -DNOREDUCE", + " #endif", + " #if defined(HAS_LAST) && !defined(BCS)", + " #error use of _last requires -DNOREDUCE", + " #endif", "#endif", "#if SYNC>0 && !defined(NOREDUCE)", - "#ifdef HAS_UNLESS", + " #ifdef HAS_UNLESS", " fprintf(efd, \"warning: use of a rendezvous stmnts in the escape\\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", + " #ifdef BFS", + " fprintf(efd, \"\t(this type of rv is also not compatible with -DBFS)\\n\");", + " #endif", + " #endif", "#endif", "#if SYNC>0 && defined(BFS)", - " fprintf(efd, \"warning: use of rendezvous in BFS mode \");", - " fprintf(efd, \"does not preserve all invalid endstates\\n\");", + " if (!noends)", + " fprintf(efd, \"warning: use of rendezvous with BFS does not preserve all invalid endstates\\n\");", "#endif", "#if !defined(REACH) && !defined(BITSTATE)", " if (iterative != 0 && a_cycles == 0)", - " fprintf(efd, \"warning: -i and -I need -DREACH to work accurately\\n\");", + " { 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\");", + " #warning -DREACH is voided by -DBITSTATE", "#endif", "#if defined(MA) && defined(REACH)", - " fprintf(efd, \"warning: -DREACH voided by -DMA\\n\");", + " #warning -DREACH is voided by -DMA", "#endif", "#if defined(FULLSTACK) && defined(CNTRSTACK)", - " fprintf(efd, \"error: cannot combine\");", - " fprintf(efd, \" -DFULLSTACK and -DCNTRSTACK\\n\");", - " pan_exit(1);", + " #error cannot combine -DFULLSTACK and -DCNTRSTACK", "#endif", "#if defined(VERI)", - "#if ACCEPT_LAB>0", - "#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", + " #if ACCEPT_LAB>0", + " #ifndef BFS", + " if (!a_cycles", + " #ifdef HAS_CODE", + " && !readtrail", + " #endif", + " #if NCORE>1", + " && core_id == 0", + " #endif", + " && !state_tables)", + " { fprintf(efd, \"warning: never claim + accept labels \");", + " fprintf(efd, \"requires -a flag to fully verify\\n\");", + " }", + " #else", + " if (verbose && !state_tables", + " #ifdef HAS_CODE", + " && !readtrail", + " #endif", + " )", + " { fprintf(efd, \"warning: verification in BFS mode \");", + " fprintf(efd, \"is restricted to safety properties\\n\");", + " }", + " #endif", + " #endif", "#endif", "#ifndef SAFETY", + " #if 0", " if (!a_cycles", - "#ifdef HAS_CODE", + " #ifdef HAS_CODE", " && !readtrail", - "#endif", - " && !state_tables)", + " #endif", + " #if NCORE>1", + " && core_id == 0", + " #endif", + " && !state_tables)", " { fprintf(efd, \"hint: this search is more efficient \");", " fprintf(efd, \"if pan.c is compiled -DSAFETY\\n\");", " }", - "#ifndef NOCOMP", + " #endif", + " #ifndef NOCOMP", " if (!a_cycles)", - " S_A = 0;", - " else", + " { S_A = 0;", + " } else", " { if (!fairness)", - " S_A = 1; /* _a_t */", - "#ifndef NOFAIR", - " else /* _a_t and _cnt[NFAIR] */", - " S_A = (&(now._cnt[0]) - (uchar *) &now) + NFAIR - 2;", + " { S_A = 1; /* _a_t */", + " #ifndef NOFAIR", + " } else /* _a_t and _cnt[NFAIR] */", + " { S_A = (&(now._cnt[0]) - (uchar *) &now) + NFAIR - 2;", " /* -2 because first two uchars in now are masked */", - "#endif", - " }", - "#endif", + " #endif", + " } }", + " #endif", "#endif", " signal(SIGINT, stopped);", - - /******************* 4.2.5 ********************/ - " if (WS == 4 && ssize >= 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 %%ld not supported\\n\", WS);", - " exit(1);", - " } else /* WS == 4 and ssize < 32 */", - " { mask = ((1L<>3);", - " }", - /****************** end **********************/ - - "#ifdef BFS", + " set_masks();", + "#if defined(BFS) || defined(BFS_PAR)", " 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", + " trpt = &trail[0]; /* precaution -- in case uerror is called early */", + "#ifdef BFS", + " ntrpt = trpt;", + "#endif", "#ifdef SVDUMP", " if (vprefix > 0)", " { char nm[64];", - " sprintf(nm, \"%%s.svd\", Source);", - " if ((svfd = creat(nm, 0666)) < 0)", + " sprintf(nm, \"%%s.svd\", PanSource);", + " if ((svfd = creat(nm, TMODE)) < 0)", " { fprintf(efd, \"couldn't create %%s\\n\", nm);", " vprefix = 0;", " } }", "#endif", "#ifdef RANDSTOR", - " srand(123);", + " srand(s_rand+HASH_NR);", /* main - RANDSTOR */ "#endif", "#if SYNC>0 && ASYNC==0", " set_recvs();", @@ -3591,6 +5971,7 @@ static char *Code2c[] = { "void", "usage(FILE *fd)", "{", + " fprintf(fd, \"%%s\\n\", SpinVersion);", " fprintf(fd, \"Valid Options are:\\n\");", "#ifndef SAFETY", "#ifdef NP", @@ -3606,6 +5987,7 @@ static char *Code2c[] = { " 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 in dot-format and stop\\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 end states\\n\");", @@ -3615,13 +5997,18 @@ static char *Code2c[] = { "#ifndef NOFAIR", " fprintf(fd, \"\t-f add weak fairness (to -a or -l)\\n\");", "#endif", - " fprintf(fd, \"\t-hN use different hash-seed N:1..32\\n\");", + " fprintf(fd, \"\t-hN use different hash-seed N:0..499 (defaults to -h0)\\n\");", + " fprintf(fd, \"\t-hash generate a random hash-polynomial for -h0 (see also -rhash)\\n\");", + " fprintf(fd, \"\t using a seed set with -RSn (default %%u)\\n\", s_rand);", " 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", + "#ifdef BCS", + " fprintf(fd, \"\t-LN set scheduling restriction to N (default 0)\\n\");", + "#endif", "#ifndef SAFETY", "#ifdef NP", " fprintf(fd, \"\t-l find non-progress cycles\\n\");", @@ -3631,69 +6018,83 @@ static char *Code2c[] = { " 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\");", + "#if NCLAIMS>1", + " fprintf(fd, \"\t-N cn -- use the claim named cn\\n\");", + " fprintf(fd, \"\t-Nn -- use claim number n\\n\");", + "#endif", " fprintf(fd, \"\t-n no listing of unreached states\\n\");", + "#ifdef PERMUTED", + " fprintf(fd, \"\t-p_permute randomize order in which processes are scheduled (see also -rhash)\\n\");", + " fprintf(fd, \"\t-p_reverse reverse order in which processes are scheduled (see also -rhash)\\n\");", + " fprintf(fd, \"\t-p_rotateN rotate by N the process scheduling order (see also -rhash)\\n\");", + "#endif", "#ifdef SVDUMP", " fprintf(fd, \"\t-pN create svfile (save N bytes per state)\\n\");", "#endif", + " fprintf(fd, \"\t-QN set time-limit on execution of N minutes\\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-r trailfilename read and execute trail in file\\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-r -PN read and execute trail - restrict trail output to proc N\\n\");", " fprintf(fd, \"\t-g read and execute trail + msc gui support\\n\");", " fprintf(fd, \"\t-S silent replay: only user defined printfs show\\n\");", "#endif", + " fprintf(fd, \"\t-RSn use randomization seed n\\n\");", + " fprintf(fd, \"\t-rhash use random hash-polynomial and randomly choose -p_rotateN, -p_permute, or p_reverse\\n\");", "#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\");", + " fprintf(fd, \"\t-Rn run n times n: [1..100] using n \");", + " fprintf(fd, \" different hash functions\\n\");", "#endif", " fprintf(fd, \"\t-T create trail files in read-only mode\\n\");", + " fprintf(fd, \"\t-t_reverse reverse order in which transitions are explored\\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);", + " fprintf(fd, \"\t-x do not overwrite an existing trail file\\n\");", + "#if NCORE>1", + " fprintf(fd, \"\t-zN handoff states below depth N to 2nd cpu (multi_core)\\n\");", + "#endif", + "#ifdef HAS_CODE", + " fprintf(fd, \"\\n\toptions -r, -C, -PN, -g, and -S can optionally be followed by\\n\");", + " fprintf(fd, \"\ta filename argument, as in \'-r filename\', naming the trailfile\\n\");", + "#endif", + "#if NCORE>1", + " multi_usage(fd);", + "#endif", " exit(1);", "}", "", "char *", - "Malloc(unsigned long n)", + "Malloc(ulong n)", "{ char *tmp;", - "#if defined(MEMCNT) || defined(MEMLIM)", - " if (memcnt+ (double) n > memlim) goto err;", + "#ifdef MEMLIM", + " if (memcnt + (double) n > memlim)", + " { printf(\"pan: reached -DMEMLIM bound\\n\");", + " goto err;", + " }", "#endif", -"#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 defined(MEMCNT) || defined(MEMLIM)", - "err:", + "#ifdef BFS_PAR", + " Uerror(\"out of non-shared memory\");", "#endif", " printf(\"pan: out of memory\\n\");", - "#if defined(MEMCNT) || defined(MEMLIM)", + "#ifdef MEMLIM", + "err:", " printf(\"\t%%g bytes used\\n\", memcnt);", " printf(\"\t%%g bytes more needed\\n\", (double) n);", - " printf(\"\t%%g bytes limit\\n\",", - " memlim);", + " printf(\"\t%%g bytes limit\\n\", memlim);", "#endif", "#ifdef COLLAPSE", " printf(\"hint: to reduce memory, recompile with\\n\");", @@ -3714,6 +6115,15 @@ static char *Code2c[] = { " printf(\" -DBITSTATE # supertrace, approximation\\n\");", "#endif", "#endif", + "#if NCORE>1", + " #ifdef FULL_TRAIL", + " printf(\" omit -DFULL_TRAIL or use pan -c0 to reduce memory\\n\");", + " #endif", + " #ifdef SEP_STATE", + " printf(\"hint: to reduce memory, recompile without\\n\");", + " printf(\" -DSEP_STATE # may be faster, but uses more memory\\n\");", + " #endif", + "#endif", " wrapup();", " }", " memcnt += (double) n;", @@ -3723,13 +6133,13 @@ static char *Code2c[] = { "#define CHUNK (100*VECTORSZ)", "", "char *", - "emalloc(unsigned long n) /* never released or reallocated */", + "emalloc(ulong n) /* never released or reallocated */", "{ char *tmp;", " if (n == 0)", " return (char *) NULL;", " if (n&(sizeof(void *)-1)) /* for proper alignment */", " n += sizeof(void *)-(n&(sizeof(void *)-1));", - " if ((unsigned long) left < n)", /* was: (left < (long)n) */ + " if ((ulong) left < n)", /* was: (left < (long)n) */ " { grow = (n < CHUNK) ? CHUNK : n;", #if 1 " have = Malloc(grow);", @@ -3754,9 +6164,15 @@ static char *Code2c[] = { "}", "void", - "Uerror(char *str)", + "dfs_Uerror(char *str)", "{ /* always fatal */", " uerror(str);", + "#if NCORE>1", + " sudden_stop(\"Uerror\");", + "#endif", + "#ifdef BFS_PAR", + " bfs_shutdown(\"Uerror\");", + "#endif", " wrapup();", "}\n", "#if defined(MA) && !defined(SAFETY)", @@ -3775,9 +6191,14 @@ static char *Code2c[] = { " trpt = getframe(depth);", "#endif", "#ifdef VERBOSE", - " printf(\"%%d State: \", depth);", + " printf(\"%%ld State: \", depth);", + "#if !defined(NOCOMP) && !defined(HC)", " for (i = 0; i < vsize; i++) printf(\"%%d%%s,\",", " ((char *)&now)[i], Mask[i]?\"*\":\"\");", + "#else", + " for (i = 0; i < vsize; i++)", + " printf(\"%%d,\", ((char *)&now)[i]);", + "#endif", " printf(\"\\n\");", "#endif", "#ifndef NOFAIR", @@ -3794,7 +6215,7 @@ static char *Code2c[] = { "#endif", "#ifdef HAS_LAST", "#ifdef VERI", - " { int d; Trail *trl;", + " { long d; Trail *trl;", " now._last = 0;", " for (d = 1; d < depth; d++)", " { trl = getframe(depth-d); /* was trl = (trpt-d); */", @@ -3820,10 +6241,10 @@ static char *Code2c[] = { " tt = trpt->o_tt; this = pptr(II);", " _m = do_reverse(t, II, trpt->o_m);", "#ifdef VERBOSE", - " printf(\"%%3d: proc %%d \", depth, II);", + " printf(\"%%3ld: proc %%d \", depth, II);", " printf(\"reverses %%d, %%d to %%d,\",", " t->forw, tt, t->st);", - " printf(\" %%s [abit=%%d,adepth=%%d,\", ", + " printf(\" %%s [abit=%%d,adepth=%%ld,\", ", " t->tp, now._a_t, A_depth);", " printf(\"tau=%%d,%%d] \\n\", ", " trpt->tau, (trpt-1)->tau);", @@ -3862,14 +6283,21 @@ static char *Code2c[] = { "#endif", "static char unwinding;", "void", - "uerror(char *str)", + "dfs_uerror(char *str)", "{ static char laststr[256];", " int is_cycle;", "", " if (unwinding) return; /* 1.4.2 */", " if (strncmp(str, laststr, 254))", - " printf(\"pan: %%s (at depth %%ld)\\n\", str,", - " (depthfound==-1)?depth:depthfound);", + "#if NCORE>1", + " cpu_printf(\"pan:%%d: %%s (at depth %%ld)\\n\", errors+1, str,", + "#else", + " printf(\"pan:%%d: %%s (at depth %%ld)\\n\", errors+1, str,", + "#endif", + "#if NCORE>1", + " (nr_handoffs * z_handoff) + ", + "#endif", + " ((depthfound == -1)?depth:depthfound));", " strncpy(laststr, str, 254);", " errors++;", "#ifdef HAS_CODE", @@ -3891,13 +6319,16 @@ static char *Code2c[] = { " depth = od;", " }", "#endif", -"#ifdef BFS", + "#if NCORE>1", + " writing_trail = 1;", + "#endif", + "#ifdef BFS", " if (depth > 1) trpt--;", - " nuerror(str);", + " nuerror();", " if (depth > 1) trpt++;", -"#else", + "#else", " putrail();", -"#endif", + "#endif", "#if defined(MA) && !defined(SAFETY)", " if (strstr(str, \" cycle\"))", " { if (every_error)", @@ -3905,20 +6336,36 @@ static char *Code2c[] = { " wrapup(); /* no recovery from unwind */", " }", "#endif", + "#if NCORE>1", + " if (search_terminated != NULL)", + " { *search_terminated |= 4; /* uerror */", + " }", + " writing_trail = 0;", + "#endif", " }", " if (!is_cycle)", " { depth--; trpt--; /* undo */", " }", -"#ifndef BFS", + "#ifndef BFS", " if (iterative != 0 && maxdepth > 0)", - " { maxdepth = (iterative == 1)?(depth-1):(depth/2);", + " { if (maxdepth > depth)", + " { maxdepth = (iterative == 1)?(depth+1):(depth/2);", + " }", " warned = 1;", " printf(\"pan: reducing search depth to %%ld\\n\",", " maxdepth);", " } else", -"#endif", + "#endif", " if (errors >= upto && upto != 0)", + " {", + "#ifdef BFS_PAR", + " bfs_shutdown(\"uerror\"); /* no return */", + "#endif", + "#if NCORE>1", + " sudden_stop(\"uerror\");", + "#endif", " wrapup();", + " }", " depthfound = -1;", "}\n", "int", @@ -3930,13 +6377,14 @@ static char *Code2c[] = { " || 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)", - " { printf(\", \\\"%%s\\\"\", mp[j].fnm);", + " { printf(\"\\t%%s:%%d\", mp[j].fnm, lno);", " break;", " }", + " if (j >= sizeof(mp)) /* fnm not found in list */", + " { printf(\"\\t%%s:%%d\", PanSource, lno); /* use default */", + " }", " printf(\", state %%d\", i);", " if (strcmp(T->tp, \"\") != 0)", " { char *q;", @@ -3951,45 +6399,120 @@ static char *Code2c[] = { "}\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]);", + "{ int i, m=0;", + "", + " if ((enum btypes) Btypes[M] == N_CLAIM", + " && claimname != NULL && strcmp(claimname, procname[M]) != 0)", + " { return;", + " }", + "", + " switch ((enum btypes) Btypes[M]) {", + " case P_PROC:", + " case A_PROC:", + " printf(\"unreached in proctype %%s\\n\", procname[M]);", + " break;", + " case I_PROC:", + " printf(\"unreached in init\\n\");", + " break;", + " case E_TRACE:", + " case N_TRACE:", + " case N_CLAIM:", + " default:", + " printf(\"unreached in claim %%s\\n\", procname[M]);", + " break;", + " }", " 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++;", + " { if (which[i] == 0", + " && (mapstate[M][i] == 0", + " || which[mapstate[M][i]] == 0))", + " { m += xrefsrc((int) src[i], mp, M, i);", + " } else", + " { m++;", + " } }", " printf(\"\t(%%d of %%d states)\\n\", N-1-m, N-1);", - "}\n", + "}", + "#if NCORE>1 && !defined(SEP_STATE)", + "static long rev_trail_cnt;", + "", + "#ifdef FULL_TRAIL", + "void", + "rev_trail(int fd, volatile Stack_Tree *st_tr)", + "{ long j; char snap[64];", + "", + " if (!st_tr)", + " { return;", + " }", + " rev_trail(fd, st_tr->prv);", + "#ifdef VERBOSE", + " printf(\"%%d (%%d) LRT [%%d,%%d] -- %%9u (root %%9u)\\n\",", + " depth, rev_trail_cnt, st_tr->pr, st_tr->t_id, st_tr, stack_last[core_id]);", + "#endif", + " if (st_tr->pr != 255)", /* still needed? */ + " { sprintf(snap, \"%%ld:%%d:%%d\\n\", ", + " rev_trail_cnt++, st_tr->pr, st_tr->t_id);", + " j = strlen(snap);", + " if (write(fd, snap, j) != j)", + " { printf(\"pan: error writing trailfile\\n\");", + " close(fd);", + " wrapup();", + " return;", + " }", + " } else /* handoff point */", + " { if (a_cycles)", + " { (void) write(fd, \"-1:-1:-1\\n\", 9);", + " } }", + "}", + "#endif", /* FULL_TRAIL */ + "#endif", /* NCORE>1 */ + "", "void", "putrail(void)", - "{ int fd; long i, j;", - " Trail *trl;", + "{ int fd;", "#if defined VERI || defined(MERGED)", " char snap[64];", "#endif", - "", + "#if NCORE==1 || defined(SEP_STATE) || !defined(FULL_TRAIL)", + " long i, j;", + " Trail *trl;", + "#endif", " fd = make_trail();", " if (fd < 0) return;", "#ifdef VERI", - " sprintf(snap, \"-2:%%d:-2\\n\", VERI);", - " write(fd, snap, strlen(snap));", + " sprintf(snap, \"-2:%%d:-2\\n\", (uchar) ((P0 *)pptr(0))->_t);", + " if (write(fd, snap, strlen(snap)) < 0) return;", "#endif", "#ifdef MERGED", " sprintf(snap, \"-4:-4:-4\\n\");", - " write(fd, snap, strlen(snap));", + " if (write(fd, snap, strlen(snap)) < 0) return;", "#endif", - " for (i = 1; i <= depth; i++)", + "#ifdef PERMUTED", + " sprintf(snap, \"-5:%%d:%%d\\n\", t_reverse, reversing&2);", + " if (write(fd, snap, strlen(snap)) < 0) return;", + "", + " sprintf(snap, \"-6:%%d:%%d\\n\", p_reorder==set_permuted, p_reorder==set_reversed);", + " if (write(fd, snap, strlen(snap)) < 0) return;", + "", + " sprintf(snap, \"-7:%%d:%%d\\n\", p_reorder==set_rotated, p_rotate);", + " if (write(fd, snap, strlen(snap)) < 0) return;", + "", + " sprintf(snap, \"-8:%%d:%%d\\n\", p_reorder==set_randrot, --s_rand);", + " if (write(fd, snap, strlen(snap)) < 0) return;", + "#endif", + "#if NCORE>1 && !defined(SEP_STATE) && defined(FULL_TRAIL)", + " rev_trail_cnt = 1;", + " enter_critical(GLOBAL_LOCK);", + " rev_trail(fd, stack_last[core_id]);", + " leave_critical(GLOBAL_LOCK);", + "#else", + " i = 1; /* trail starts at position 1 */", + " #if NCORE>1 && defined(SEP_STATE)", + " if (cur_Root.m_vsize > 0) { i++; depth++; }", + " #endif", + " for ( ; i <= depth; i++)", " { if (i == depthfound+1)", - " write(fd, \"-1:-1:-1\\n\", 9);", + " { if (write(fd, \"-1:-1:-1\\n\", 9) != 9)", + " { goto notgood;", + " } }", " trl = getframe(i);", " if (!trl->o_t) continue;", " if (trl->o_pm&128) continue;", @@ -3997,12 +6520,16 @@ static char *Code2c[] = { " i, trl->pr, trl->o_t->t_id);", " j = strlen(snap);", " if (write(fd, snap, j) != j)", - " { printf(\"pan: error writing trailfile\\n\");", + " {", + "notgood: printf(\"pan: error writing trailfile\\n\");", " close(fd);", " wrapup();", - " }", - " }", + " } }", + "#endif", " close(fd);", + "#if NCORE>1", + " cpu_printf(\"pan: wrote trailfile\\n\");", + "#endif", "}\n", "void", "sv_save(void) /* push state vector onto save stack */", @@ -4022,13 +6549,16 @@ static char *Code2c[] = { "#if SYNC", " svtack->o_boq = boq;", "#endif", + "#ifdef TRIX", + " sv_populate();", + "#endif", " svtack->o_delta = vsize; /* don't compress */", " 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);", + " cpu_printf(\"%%d: sv_save\\n\", depth);", "#endif", "}\n", "void", @@ -4038,7 +6568,9 @@ static char *Code2c[] = { "#if SYNC", " boq = svtack->o_boq;", "#endif", - + "#ifdef TRIX", + " re_populate();", + "#endif", "#if defined(C_States) && (HAS_TRACK==1)", "#ifdef HAS_STACK", " c_unstack((uchar *) &(svtack->c_stack[0]));", @@ -4049,78 +6581,144 @@ static char *Code2c[] = { " if (vsize != svtack->o_delta)", " Uerror(\"sv_restor\");", " if (!svtack->lst)", - " Uerror(\"error: v_restor\");", + " Uerror(\"error: sv_restor\");", " svtack = svtack->lst;", "#ifdef DEBUG", - " printf(\" sv_restor\\n\");", + " cpu_printf(\" sv_restor\\n\");", "#endif", - "}\n", + "}", + "", "void", "p_restor(int h)", - "{ int i; char *z = (char *) &now;\n", + "{ int i;", + " char *z = (char *) &now;\n", + "", + "#ifdef BFS_PAR", + " bfs_prepmask(1); /* p_restor */", + "#endif", + "#ifndef TRIX", " proc_offset[h] = stack->o_offset;", " proc_skip[h] = (uchar) stack->o_skip;", + "#else", + " char *oi;", + " #ifdef V_TRIX", + " printf(\"%%4d: p_restor %%d\\n\", depth, h);", + " #endif", + "#endif", "#ifndef XUSAFE", " p_name[h] = stack->o_name;", "#endif", - "#ifndef NOCOMP", + "#ifdef TRIX", + " vsize += sizeof(char *);", + " #ifndef BFS", + " if (processes[h] != NULL || freebodies == NULL)", + " { Uerror(\"processes error\");", + " }", + " processes[h] = freebodies;", + " freebodies = freebodies->nxt;", + " processes[h]->nxt = (TRIX_v6 *) 0;", + " processes[h]->modified = 1; /* p_restor */", + " #endif", + " processes[h]->parent_pid = stack->parent;", + " processes[h]->psize = stack->o_delta;", + " memcpy((char *)pptr(h), stack->b_ptr, stack->o_delta);", + " oi = stack->b_ptr;", + "#else", + " #if !defined(NOCOMP) && !defined(HC)", " for (i = vsize + stack->o_skip; i > vsize; i--)", " Mask[i-1] = 1; /* align */", - "#endif", + " #endif", " vsize += stack->o_skip;", " memcpy(z+vsize, stack->body, stack->o_delta);", " vsize += stack->o_delta;", - "#ifndef NOVSZ", - " now._vsz = vsize;", - "#endif", - "#ifndef NOCOMP", - " for (i = 1; i <= Air[((P0 *)pptr(h))->_t]; i++)", - " Mask[vsize - i] = 1; /* pad */", - " Mask[proc_offset[h]] = 1; /* _pid */", - "#endif", + " #if !defined(NOCOMP) && !defined(HC)", + " for (i = 1; i <= Air[((P0 *)pptr(h))->_t]; i++)", + " Mask[vsize - i] = 1; /* pad */", + " Mask[proc_offset[h]] = 1; /* _pid */", + " #endif", " if (BASE > 0 && h > 0)", " ((P0 *)pptr(h))->_pid = h-BASE;", " else", " ((P0 *)pptr(h))->_pid = h;", - " i = stack->o_delqs;", + " #ifdef BFS_PAR", + " bfs_fixmask(1); /* p_restor */", + " #endif", + "#endif", " now._nr_pr += 1;", - " if (!stack->lst) /* debugging */", + "#ifndef NOVSZ", + " now._vsz = vsize;", + "#endif", + " i = stack->o_delqs;", + " if (!stack->lst)", " Uerror(\"error: p_restor\");", " stack = stack->lst;", " this = pptr(h);", " while (i-- > 0)", " q_restor();", + "#ifdef TRIX", + " re_mark_all(1); /* p_restor - all chans move up in _ids_ */", + " now._ids_[h] = oi; /* restor the original contents */", + "#endif", "}\n", "void", "q_restor(void)", - "{ char *z = (char *) &now;", - "#ifndef NOCOMP", - " int k, k_end;", - "#endif", - " q_offset[now._nr_qs] = stack->o_offset;", - " q_skip[now._nr_qs] = (uchar) stack->o_skip;", - "#ifndef XUSAFE", - " q_name[now._nr_qs] = stack->o_name;", - "#endif", + "{ int h = now._nr_qs;", + "#ifdef TRIX", + " #ifdef V_TRIX", + " printf(\"%%4d: q_restor %%d\\n\", depth, h);", + " #endif", + " vsize += sizeof(char *);", + " #ifndef BFS", + " if (channels[h] != NULL || freebodies == NULL)", + " { Uerror(\"channels error\");", + " }", + " channels[h] = freebodies;", + " freebodies = freebodies->nxt;", + " channels[h]->nxt = (TRIX_v6 *) 0;", + " channels[h]->modified = 1; /* q_restor */", + " #endif", + " channels[h]->parent_pid = stack->parent;", + " channels[h]->psize = stack->o_delta;", + " memcpy((char *)qptr(h), stack->b_ptr, stack->o_delta);", + " now._ids_[now._nr_pr + h] = stack->b_ptr;", + "#else", + " char *z = (char *) &now;", + " #ifndef NOCOMP", + " int k, k_end;", + " #endif", + " #ifdef BFS_PAR", + " bfs_prepmask(2); /* q_restor */", + " #endif", + " q_offset[h] = stack->o_offset;", + " q_skip[h] = (uchar) stack->o_skip;", " vsize += stack->o_skip;", " memcpy(z+vsize, stack->body, stack->o_delta);", " vsize += stack->o_delta;", + "#endif", + "#ifndef XUSAFE", + " q_name[h] = stack->o_name;", + "#endif", "#ifndef NOVSZ", " now._vsz = vsize;", "#endif", " now._nr_qs += 1;", - "#ifndef NOCOMP", - " k_end = stack->o_offset;", - " k = k_end - stack->o_skip;", - "#if SYNC", - "#ifndef BFS", - " if (q_zero(now._nr_qs)) k_end += stack->o_delta;", + "#ifndef TRIX", + " #if !defined(NOCOMP) && !defined(HC)", + " k_end = stack->o_offset;", + " k = k_end - stack->o_skip;", + " #if SYNC", + " #ifndef BFS", + " if (q_zero(now._nr_qs)) k_end += stack->o_delta;", + " #endif", + " #endif", + " for ( ; k < k_end; k++)", + " Mask[k] = 1;", + " #endif", + " #ifdef BFS_PAR", + " bfs_fixmask(2); /* q_restor */", + " #endif", "#endif", - "#endif", - " for ( ; k < k_end; k++)", - " Mask[k] = 1;", - "#endif", - " if (!stack->lst) /* debugging */", + " if (!stack->lst)", " Uerror(\"error: q_restor\");", " stack = stack->lst;", "}", @@ -4163,7 +6761,46 @@ static char *Code2c[] = { "#ifndef NOCOMP", " int o_vsize = vsize;", "#endif", - " if (h+1 != (int) now._nr_pr) return 0;\n", + " if (h+1 != (int) now._nr_pr)", + " { return 0;", + " }", + "#ifdef TRIX", + " #ifdef V_TRIX", + " printf(\"%%4d: delproc %%d -- parent %%d\\n\", depth, h, processes[h]->parent_pid);", + " if (now._nr_qs > 0)", + " printf(\" top channel: %%d -- parent %%d\\n\", now._nr_qs-1, channels[now._nr_qs-1]->parent_pid);", + " #endif", + " while (now._nr_qs > 0", + " && channels[now._nr_qs-1]->parent_pid == processes[h]->parent_pid)", + " { delq(sav);", + " i++;", + " }", + " d = processes[h]->psize;", + " if (sav)", + " { if (!stack->nxt)", + " { stack->nxt = (_Stack *) emalloc(sizeof(_Stack));", + " stack->nxt->lst = stack;", + " smax++;", + " }", + " stack = stack->nxt;", + " #ifndef XUSAFE", + " stack->o_name = p_name[h];", + " #endif", + " stack->parent = processes[h]->parent_pid;", + " stack->o_delta = d;", + " stack->o_delqs = i;", + " stack->b_ptr = now._ids_[h];", /* new 6.1 */ + " }", + " memset((char *)pptr(h), 0, d);", + " #ifndef BFS", + " processes[h]->nxt = freebodies;", + " freebodies = processes[h];", + " processes[h] = (TRIX_v6 *) 0;", + " #endif", + " vsize -= sizeof(char *);", + " now._nr_pr -= 1;", + " re_mark_all(-1); /* delproc - all chans move down in _ids_ */", + "#else", " while (now._nr_qs", " && q_offset[now._nr_qs-1] > proc_offset[h])", " { delq(sav);", @@ -4172,80 +6809,116 @@ static char *Code2c[] = { " d = vsize - proc_offset[h];", " if (sav)", " { if (!stack->nxt)", - " { stack->nxt = (Stack *)", - " emalloc(sizeof(Stack));", - " stack->nxt->body = ", - " emalloc(Maxbody*sizeof(char));", + " { stack->nxt = (_Stack *) emalloc(sizeof(_Stack));", + " stack->nxt->body = emalloc(Maxbody * sizeof(char));", " stack->nxt->lst = stack;", " smax++;", " }", " stack = stack->nxt;", " stack->o_offset = proc_offset[h];", - "#if VECTORSZ>32000", + " #if VECTORSZ>32000", " stack->o_skip = (int) proc_skip[h];", - "#else", + " #else", " stack->o_skip = (short) proc_skip[h];", - "#endif", - "#ifndef XUSAFE", + " #endif", + " #ifndef XUSAFE", " stack->o_name = p_name[h];", - "#endif", + " #endif", " stack->o_delta = d;", " stack->o_delqs = i;", " memcpy(stack->body, (char *)pptr(h), d);", " }", " vsize = proc_offset[h];", - " now._nr_pr = now._nr_pr - 1;", + " now._nr_pr -= 1;", " memset((char *)pptr(h), 0, d);", " vsize -= (int) proc_skip[h];", + " #if !defined(NOCOMP) && !defined(HC)", + " #ifdef BFS_PAR", + " bfs_prepmask(3); /* delproc - no chance in proc_offset or proc_skip */", + " #endif", + " for (i = vsize; i < o_vsize; i++)", + " Mask[i] = 0; /* reset */", + " #ifdef BFS_PAR", + " bfs_fixmask(3); /* delproc */", + " #endif", + " #endif", + "#endif", "#ifndef NOVSZ", " now._vsz = vsize;", "#endif", - "#ifndef NOCOMP", - " for (i = vsize; i < o_vsize; i++)", - " Mask[i] = 0; /* reset */", - "#endif", " return 1;", "}\n", "void", "delq(int sav)", "{ int h = now._nr_qs - 1;", + "#ifdef TRIX", + " int d = channels[now._nr_qs - 1]->psize;", + "#else", " int d = vsize - q_offset[now._nr_qs - 1];", + "#endif", "#ifndef NOCOMP", " int k, o_vsize = vsize;", "#endif", " if (sav)", " { if (!stack->nxt)", - " { stack->nxt = (Stack *)", - " emalloc(sizeof(Stack));", - " stack->nxt->body = ", - " emalloc(Maxbody*sizeof(char));", + " { stack->nxt = (_Stack *) emalloc(sizeof(_Stack));", + "#ifndef TRIX", + " stack->nxt->body = emalloc(Maxbody * sizeof(char));", + "#endif", " stack->nxt->lst = stack;", " smax++;", " }", " stack = stack->nxt;", - " stack->o_offset = q_offset[h];", - "#if VECTORSZ>32000", - " stack->o_skip = (int) q_skip[h];", + "#ifdef TRIX", + " stack->parent = channels[h]->parent_pid;", + " stack->b_ptr = now._ids_[h];", /* new 6.1 */ "#else", + " stack->o_offset = q_offset[h];", + " #if VECTORSZ>32000", + " stack->o_skip = (int) q_skip[h];", + " #else", " stack->o_skip = (short) q_skip[h];", + " #endif", "#endif", - "#ifndef XUSAFE", + " #ifndef XUSAFE", " stack->o_name = q_name[h];", - "#endif", + " #endif", " stack->o_delta = d;", + "#ifndef TRIX", " memcpy(stack->body, (char *)qptr(h), d);", + "#endif", " }", + "#ifdef TRIX", + " vsize -= sizeof(char *);", + " #ifdef V_TRIX", + " printf(\"%%4d: delq %%d parent %%d\\n\", depth, h, channels[h]->parent_pid);", + " #endif", + "#else", " vsize = q_offset[h];", - " now._nr_qs = now._nr_qs - 1;", - " memset((char *)qptr(h), 0, d);", " vsize -= (int) q_skip[h];", + " #if !defined(NOCOMP) && !defined(HC)", + " #ifdef BFS_PAR", + " bfs_prepmask(3); /* delq - no change in q_offset or q_skip */", + " #endif", + " for (k = vsize; k < o_vsize; k++)", + " Mask[k] = 0; /* reset */", + " #ifdef BFS_PAR", + " bfs_fixmask(3); /* delq */", + " #endif", + " #endif", + "#endif", + " now._nr_qs -= 1;", + " memset((char *)qptr(h), 0, d);", + "#ifdef TRIX", + " #ifndef BFS", + " channels[h]->nxt = freebodies;", + " freebodies = channels[h];", + " channels[h] = (TRIX_v6 *) 0;", + " #endif", + "#endif", "#ifndef NOVSZ", " now._vsz = vsize;", "#endif", - "#ifndef NOCOMP", - " for (k = vsize; k < o_vsize; k++)", - " Mask[k] = 0; /* reset */", - "#endif", "}\n", "int", "qs_empty(void)", @@ -4265,7 +6938,7 @@ static char *Code2c[] = { " return 0;", " }", " if (strict) return qs_empty();", - "#if defined(EVENT_TRACE) && !defined(OTIM)", + "#if defined(EVENT_TRACE)", " if (!stopstate[EVENT_TRACE][now._event] && !a_cycles)", " { printf(\"pan: event_trace not completed\\n\");", " return 0;", @@ -4273,55 +6946,54 @@ static char *Code2c[] = { "#endif", " return 1;", "}\n", - "#ifndef SAFETY", + "#if !defined(SAFETY) && !defined(BFS)", "void", "checkcycles(void)", "{ uchar o_a_t = now._a_t;", - "#ifndef NOFAIR", - " uchar o_cnt = now._cnt[1];", - "#endif", - "#ifdef FULLSTACK", - "#ifndef MA", - " struct H_el *sv = trpt->ostate; /* save */", - "#else", - " uchar prov = trpt->proviso; /* save */", - "#endif", - "#endif", - "#ifdef DEBUG", - " { int i; uchar *v = (uchar *) &now;", - " printf(\" set Seed state \");", - "#ifndef NOFAIR", - " if (fairness) printf(\"(cnt = %%d:%%d, nrpr=%%d) \",", - " now._cnt[0], now._cnt[1], now._nr_pr);", - "#endif", - " /* for (i = 0; i < n; i++) printf(\"%%d,\", v[i]); */", - " printf(\"\\n\");", - " }", - " printf(\"%%d: cycle check starts\\n\", depth);", - "#endif", + " #ifndef NOFAIR", + " uchar o_cnt = now._cnt[1];", + " #endif", + " #ifdef FULLSTACK", + " #ifndef MA", + " H_el *sv = trpt->ostate; /* save */", + " #else", + " uchar prov = trpt->proviso; /* save */", + " #endif", + " #endif", + " #ifdef DEBUG", + " { int i; uchar *v = (uchar *) &now;", + " printf(\" set Seed state \");", + " #ifndef NOFAIR", + " if (fairness)", + " printf(\"(cnt = %%d:%%d, nrpr=%%d) \",", + " now._cnt[0], now._cnt[1], now._nr_pr);", + " #endif", + " /* for (i = 0; i < n; i++) printf(\"%%d,\", v[i]); */", + " printf(\"\\n\");", + " }", + " printf(\"%%ld: cycle check starts\\n\", depth);", + " #endif", " now._a_t |= (1|16|32);", - " /* 1 = 2nd DFS; (16|32) to help hasher */", - "#ifndef NOFAIR", -#if 0 - " if (fairness)", - " { now._a_t &= ~2; /* pre-apply Rule 3 */", - " now._cnt[1] = 0;", /* reset both a-bit and cnt=0 */ - " /* avoid matching seed on claim stutter on this state */", - " }", -#else - " now._cnt[1] = now._cnt[0];", -#endif - "#endif", + " /* 1 = 2nd DFS; (16|32) to improve hashing */", + " #ifndef NOFAIR", + " now._cnt[1] = now._cnt[0];", + " #endif", " memcpy((char *)&A_Root, (char *)&now, vsize);", " A_depth = depthfound = depth;", - " new_state(); /* start 2nd DFS */", + + " #if NCORE>1", + " mem_put_acc();", /* handoff accept states */ + " #else", + " new_state(); /* start 2nd DFS */", + " #endif", + " now._a_t = o_a_t;", - "#ifndef NOFAIR", - " now._cnt[1] = o_cnt;", - "#endif", + " #ifndef NOFAIR", + " now._cnt[1] = o_cnt;", + " #endif", " A_depth = 0; depthfound = -1;", "#ifdef DEBUG", - " printf(\"%%d: cycle check returns\\n\", depth);", + " printf(\"%%ld: cycle check returns\\n\", depth);", "#endif", "#ifdef FULLSTACK", "#ifndef MA", @@ -4331,60 +7003,120 @@ static char *Code2c[] = { "#endif", "#endif", "}", - "#endif\n", + "#endif", + "", "#if defined(FULLSTACK) && defined(BITSTATE)", - "struct H_el *Free_list = (struct H_el *) 0;", + "H_el *Free_list = (H_el *) 0;", "void", "onstack_init(void) /* to store stack states in a bitstate search */", - "{ S_Tab = (struct H_el **) emalloc(maxdepth*sizeof(struct H_el *));", + "{ S_Tab = (H_el **) emalloc(maxdepth*sizeof(H_el *));", "}", - "struct H_el *", - "grab_state(int n)", - "{ struct H_el *v, *last = 0;", - " if (H_tab == S_Tab)", - " { for (v = Free_list; v && ((int) v->tagged >= n); v=v->nxt)", - " { if ((int) v->tagged == n)", - " { if (last)", - " last->nxt = v->nxt;", - " else", - "gotcha: Free_list = v->nxt;", - " v->tagged = 0;", - " v->nxt = 0;", - "#ifdef COLLAPSE", - " v->ln = 0;", - "#endif", - " return v;", - " }", - " Fh++; last=v;", - " }", - " /* new: second try */", - " v = Free_list;", /* try to avoid emalloc */ - " if (v && ((int) v->tagged >= n))", - " goto gotcha;", - " ngrabs++;", - " }", - " return (struct H_el *)", - " emalloc(sizeof(struct H_el)+n-sizeof(unsigned));", - "}\n", - "#else", - "#define grab_state(n) (struct H_el *) \\", - " emalloc(sizeof(struct H_el)+n-sizeof(unsigned));", "#endif", + + "#if !defined(BFS_PAR)", + " #if defined(FULLSTACK) && defined(BITSTATE)", + "H_el *", + "grab_state(int n)", + "{ H_el *v, *last = 0;", + " if (H_tab == S_Tab)", + " { for (v = Free_list; v && ((int) v->tagged >= n); v=v->nxt)", + " { if ((int) v->tagged == n)", + " { if (last)", + " last->nxt = v->nxt;", + " else", + "gotcha: Free_list = v->nxt;", + " v->tagged = 0;", + " v->nxt = 0;", + " #ifdef COLLAPSE", + " v->ln = 0;", + " #endif", + " return v;", + " }", + " Fh++; last=v;", + " }", + " /* new: second try */", + " v = Free_list;", /* try to avoid emalloc */ + " if (v && ((int) v->tagged >= n))", + " goto gotcha;", + " ngrabs++;", + " }", + " return (H_el *) emalloc(sizeof(H_el)+n-sizeof(unsigned));", + "}", + " #else", /* !FULLSTACK || !BITSTATE */ + "#if NCORE>1", + "H_el *", + "grab_state(int n)", + "{ H_el *grab_shared(int);", + " return grab_shared(sizeof(H_el)+n-sizeof(unsigned));", + "}", + "#else", /* ! NCORE>1 */ + "#ifndef AUTO_RESIZE", + " #define grab_state(n) (H_el *) \\", + " emalloc(sizeof(H_el)+n-sizeof(ulong));", + "#else", /* AUTO_RESIZE */ + "H_el *", + "grab_state(int n)", + "{ H_el *p;", + " int cnt = sizeof(H_el)+n-sizeof(ulong);", + "#ifndef MA", + " if (reclaim_size >= cnt+WS)", + " { if ((cnt & (WS-1)) != 0) /* alignment */", + " { cnt += WS - (cnt & (WS-1));", + " }", + " p = (H_el *) reclaim_mem;", + " reclaim_mem += cnt;", + " reclaim_size -= cnt;", + " memset(p, 0, cnt);", + " } else", + "#endif", + " { p = (H_el *) emalloc(cnt);", + " }", + " return p;", + "}", + "#endif", /* AUTO_RESIZE */ + "#endif", /* NCORE>1 */ + " #endif", /* FULLSTACK && !BITSTATE */ + "#else", /* BFS_PAR */ + " extern volatile uchar *sh_pre_malloc(ulong);", + " extern volatile uchar *sh_malloc(ulong);", + " H_el *", + " grab_state(int n) /* bfs_par */", + " { volatile uchar *rval = NULL;", + " int m = sizeof(H_el) + n - sizeof(unsigned);", + "", + " if (n == 0) m = m/n;", + " #ifdef BFS_SEP_HASH", + " rval = emalloc((ulong) m);", + " #else", + " rval = sh_malloc((ulong) m);", + " #endif", + " memset((void *) rval, 0, (size_t) m);", + "", + " return (H_el *) rval;", + " }", + "#endif", /* BFS_PAR */ + "#ifdef COLLAPSE", - "unsigned long", + "ulong", "ordinal(char *v, long n, short tp)", - "{ struct H_el *tmp, *ntmp; long m;", - " struct H_el *olst = (struct H_el *) 0;", + "{ H_el *tmp, *ntmp; long m;", + " H_el *olst = (H_el *) 0;", " s_hash((uchar *)v, n);", - " tmp = H_tab[j1];", + + "#if defined(BFS_PAR) && !defined(BFS_SEP_HASH)", + " e_critical(BFS_ID); /* bfs_par / collapse */", + "#endif", + "#if NCORE>1 && !defined(SEP_STATE)", + " enter_critical(CS_ID); /* uses spinlock - 1..128 */", + "#endif", + " tmp = H_tab[j1_spin];", " if (!tmp)", " { tmp = grab_state(n);", - " H_tab[j1] = tmp;", + " H_tab[j1_spin] = tmp;", " } else", " for ( ;; olst = tmp, tmp = tmp->nxt)", - " { m = memcmp(((char *)&(tmp->state)), v, n);", - " if (n == tmp->ln)", - " {", + " { if (n == tmp->ln)", + " { m = memcmp(((char *)&(tmp->state)), v, n);", " if (m == 0)", " goto done;", " if (m < 0)", @@ -4392,7 +7124,7 @@ static char *Code2c[] = { "Insert: ntmp = grab_state(n);", " ntmp->nxt = tmp;", " if (!olst)", - " H_tab[j1] = ntmp;", + " H_tab[j1_spin] = ntmp;", " else", " olst->nxt = ntmp;", " tmp = ntmp;", @@ -4410,15 +7142,38 @@ static char *Code2c[] = { " else if (!tmp->nxt)", " goto Append;", " }", + "#if NCORE>1 && !defined(SEP_STATE)", + " enter_critical(GLOBAL_LOCK);", + "#endif", + "#ifdef BFS_PAR", + " e_critical(BFS_ORD); /* bfs_par */", + "#endif", " m = ++ncomps[tp];", + "#ifdef BFS_PAR", + " x_critical(BFS_ORD);", + "#endif", + "#if NCORE>1 && !defined(SEP_STATE)", + " leave_critical(GLOBAL_LOCK);", + "#endif", "#ifdef FULLSTACK", " tmp->tagged = m;", "#else", " tmp->st_id = m;", "#endif", + "#if defined(AUTO_RESIZE) && !defined(BITSTATE)", + " tmp->m_K1 = K1;", + "#endif", " memcpy(((char *)&(tmp->state)), v, n);", " tmp->ln = n;", "done:", + + "#if NCORE>1 && !defined(SEP_STATE)", + " leave_critical(CS_ID);", + "#endif", + "#if defined(BFS_PAR) && !defined(BFS_SEP_HASH)", + " x_critical(BFS_ID);", + "#endif", + "#ifdef FULLSTACK", " return tmp->tagged;", "#else", @@ -4430,7 +7185,7 @@ static char *Code2c[] = { "compress(char *vin, int nin) /* collapse compression */", "{ char *w, *v = (char *) &comp_now;", " int i, j;", - " unsigned long n;", + " ulong n;", " static char *x;", " static uchar nbytes[513]; /* 1 + 256 + 256 */", " static unsigned short nbytelen;", @@ -4523,7 +7278,7 @@ static char *Code2c[] = { "#if VECTORSZ<65536", " w = (char *) &(now._vsz) + sizeof(unsigned short);", "#else", - " w = (char *) &(now._vsz) + sizeof(unsigned long);", + " w = (char *) &(now._vsz) + sizeof(ulong);", "#endif", "#endif", " x = scratch;", @@ -4535,8 +7290,14 @@ static char *Code2c[] = { " else", " n = pptr(0) - (uchar *) w;", " j = w - (char *) &now;", + "", + "#if !defined(NOCOMP) && !defined(HC)", " for (i = 0; i < (int) n; i++, w++)", " if (!Mask[j++]) *x++ = *w;", + "#else", + " memcpy(x, w, n); x += n;", + "#endif", + "", "#ifndef SEPQS", " for (i = 0; i < (int) now._nr_qs; i++)", " x += col_q(i, x);", @@ -4572,7 +7333,7 @@ static char *Code2c[] = { " return v - (char *)&comp_now;", "}", -"#else", +"#else", /* !COLLAPSE */ "#if !defined(NOCOMP)", "int", "compress(char *vin, int n) /* default compression */", @@ -4600,11 +7361,56 @@ static char *Code2c[] = { " char *vv = vin;", " char *v = (char *) &comp_now;", " int i;", - " for (i = 0; i < n; i++, vv++)", - " if (!Mask[i]) *v++ = *vv;", - " for (i = 0; i < WS-1; i++)", - " *v++ = 0;", - " v -= i;", + " #ifndef NO_FAST_C", /* disable faster compress */ + " int r = 0, unroll = n/8;", /* most sv are much longer */ + " if (unroll > 0)", + " { i = 0;", + " while (r++ < unroll)", + " { /* unroll 8 times, avoid ifs */", + " /* 1 */ *v = *vv++; v += 1 - Mask[i++];", + " /* 2 */ *v = *vv++; v += 1 - Mask[i++];", + " /* 3 */ *v = *vv++; v += 1 - Mask[i++];", + " /* 4 */ *v = *vv++; v += 1 - Mask[i++];", + " /* 5 */ *v = *vv++; v += 1 - Mask[i++];", + " /* 6 */ *v = *vv++; v += 1 - Mask[i++];", + " /* 7 */ *v = *vv++; v += 1 - Mask[i++];", + " /* 8 */ *v = *vv++; v += 1 - Mask[i++];", + " }", + " r = n - i; /* the rest, at most 7 */", + " switch (r) {", + " case 7: *v = *vv++; v += 1 - Mask[i++];", + " case 6: *v = *vv++; v += 1 - Mask[i++];", + " case 5: *v = *vv++; v += 1 - Mask[i++];", + " case 4: *v = *vv++; v += 1 - Mask[i++];", + " case 3: *v = *vv++; v += 1 - Mask[i++];", + " case 2: *v = *vv++; v += 1 - Mask[i++];", + " case 1: *v = *vv++; v += 1 - Mask[i++];", + " case 0: break;", + " }", + " n = i = v - (char *)&comp_now; /* bytes written so far */", + " r = (n+WS-1)/WS; /* in words, rounded up */", + " r *= WS; /* total bytes to fill */", + " i = r - i; /* remaining bytes */", + " switch (i) {", /* fill word */ + " case 7: *v++ = 0; /* fall thru */", + " case 6: *v++ = 0;", + " case 5: *v++ = 0;", + " case 4: *v++ = 0;", + " case 3: *v++ = 0;", + " case 2: *v++ = 0;", + " case 1: *v++ = 0;", + " case 0: break;", + " default: Uerror(\"unexpected wordsize\");", + " }", + " v -= i;", + " } else", + " #endif", + " { for (i = 0; i < n; i++, vv++)", + " if (!Mask[i]) *v++ = *vv;", + " for (i = 0; i < WS-1; i++)", + " *v++ = 0;", + " v -= i;", + " }", "#if 0", " printf(\"compress %%d -> %%d\\n\",", " n, v - (char *)&comp_now);", @@ -4613,7 +7419,7 @@ static char *Code2c[] = { "#endif", "}", "#endif", -"#endif", +"#endif", /* COLLAPSE */ "#if defined(FULLSTACK) && defined(BITSTATE)", "#if defined(MA)", "#if !defined(onstack_now)", @@ -4628,9 +7434,15 @@ static char *Code2c[] = { "#else", "void", "onstack_zap(void)", - "{ struct H_el *v, *w, *last = 0;", - " struct H_el **tmp = H_tab;", - " char *nv; int n, m;\n", + "{ H_el *v, *w, *last = 0;", + " H_el **tmp = H_tab;", + " char *nv; int n, m;", + " static char warned = 0;", + "#if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)", + " uchar was_last = now._last;", + " now._last = 0;", + "#endif", + "", " H_tab = S_Tab;", "#ifndef NOCOMP", " nv = (char *) &comp_now;", @@ -4648,7 +7460,7 @@ static char *Code2c[] = { " s_hash((uchar *)nv, n);", "#endif", " H_tab = tmp;", - " for (v = S_Tab[j1]; v; Zh++, last=v, v=v->nxt)", + " for (v = S_Tab[j1_spin]; v; Zh++, last=v, v=v->nxt)", " { m = memcmp(&(v->state), nv, n);", " if (m == 0)", " goto Found;", @@ -4656,101 +7468,190 @@ static char *Code2c[] = { " break;", " }", "/* NotFound: */", - " Uerror(\"stack out of wack - zap\");", - " return;", + "#ifndef ZAPH", + " /* seen this happen, likely harmless in multicore */", + " if (warned == 0)", + " { /* Uerror(\"stack out of wack - zap\"); */", + " cpu_printf(\"pan: warning, stack incomplete\\n\");", + " warned = 1;", + " }", + "#endif", + " goto done;", "Found:", " ZAPS++;", " if (last)", " last->nxt = v->nxt;", " else", - " S_Tab[j1] = v->nxt;", + " S_Tab[j1_spin] = v->nxt;", " v->tagged = (unsigned) n;", "#if !defined(NOREDUCE) && !defined(SAFETY)", " v->proviso = 0;", "#endif", - " v->nxt = last = (struct H_el *) 0;", + " v->nxt = last = (H_el *) 0;", " for (w = Free_list; w; Fa++, last=w, w = w->nxt)", " { if ((int) w->tagged <= n)", " { if (last)", - " { v->nxt = w; /* was: v->nxt = w->nxt; */", + " { v->nxt = w;", " last->nxt = v;", " } else", " { v->nxt = Free_list;", " Free_list = v;", " }", - " return;", + " goto done;", " }", " if (!w->nxt)", " { w->nxt = v;", - " return;", + " goto done;", " } }", " Free_list = v;", + "done:", + "#if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)", + " now._last = was_last;", + "#endif", + " return;", "}", - "void", - "onstack_put(void)", - "{ struct H_el **tmp = H_tab;", - " H_tab = S_Tab;", - " if (hstore((char *)&now, vsize) != 0)", - "#if defined(BITSTATE) && defined(LC)", - " printf(\"pan: warning, double stack entry\\n\");", - "#else", - " Uerror(\"cannot happen - unstack_put\");", - "#endif", - " H_tab = tmp;", - " trpt->ostate = Lstate;", - " PUT++;", - "}", - "int", - "onstack_now(void)", - "{ struct H_el *tmp;", - " struct H_el **tmp2 = H_tab;", - " char *v; int n, m = 1;\n", - " H_tab = S_Tab;", - "#ifdef NOCOMP", - "#if defined(BITSTATE) && defined(LC)", - " v = (char *) &comp_now;", - " n = compact_stack((char *)&now, vsize);", - "#else", - " v = (char *) &now;", - " n = vsize;", - "#endif", - "#else", - " v = (char *) &comp_now;", - " n = compress((char *)&now, vsize);", - "#endif", - "#if !defined(HC) && !(defined(BITSTATE) && defined(LC))", - " s_hash((uchar *)v, n);", - "#endif", - " H_tab = tmp2;", - " for (tmp = S_Tab[j1]; tmp; Zn++, tmp = tmp->nxt)", - " { m = memcmp(((char *)&(tmp->state)),v,n);", - " if (m <= 0)", - " { Lstate = (struct H_el *) tmp;", - " break;", - " } }", - " PROBE++;", - " return (m == 0);", - "}", - "#endif", -"#endif", + "", + "#ifndef BFS_PAR", + " void", + " onstack_put(void)", + " { H_el **tmp = H_tab;", + " #if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)", + " uchar was_last = now._last;", + " now._last = 0;", + " #endif", + " H_tab = S_Tab;", + " if (h_store((char *)&now, vsize) != 0)", + " #if defined(BITSTATE) && defined(LC)", + " printf(\"pan: warning, double stack entry\\n\");", + " #else", + " #ifndef ZAPH", + " Uerror(\"cannot happen - unstack_put\");", + " #endif", + " #endif", + " H_tab = tmp;", + " trpt->ostate = Lstate;", + " PUT++;", + " #if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)", + " now._last = was_last;", + " #endif", + " }", + " int", + " onstack_now(void)", + " { H_el *tmp;", + " H_el **tmp2 = H_tab;", + " char *v; int n, m = 1;\n", + " #if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)", + " uchar was_last = now._last;", + " now._last = 0;", + " #endif", + " H_tab = S_Tab;", + " #ifdef NOCOMP", + " #if defined(BITSTATE) && defined(LC)", + " v = (char *) &comp_now;", + " n = compact_stack((char *)&now, vsize);", + " #else", + " v = (char *) &now;", + " n = vsize;", + " #endif", + " #else", + " v = (char *) &comp_now;", + " n = compress((char *)&now, vsize);", + " #endif", + " #if !defined(HC) && !(defined(BITSTATE) && defined(LC))", + " s_hash((uchar *)v, n);", + " #endif", + " H_tab = tmp2;", + " for (tmp = S_Tab[j1_spin]; tmp; Zn++, tmp = tmp->nxt)", + " { m = memcmp(((char *)&(tmp->state)),v,n);", + " if (m <= 0)", + " { Lstate = (H_el *) tmp; /* onstack_now */", + " break;", + " } }", + " PROBE++;", + " #if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)", + " now._last = was_last;", + " #endif", + " return (m == 0);", + " }", + "#endif", /* !BFS_PAR */ +"#endif", /* !MA */ + "#endif", /* FULLSTACK && BITSTATE */ - "#ifndef BITSTATE", + "#ifdef BITSTATE", + "void init_SS(ulong);", + "", + "void", + "sinit(void)", + "{", + " if (udmem)", + " { udmem *= 1024L*1024L;", + " #if NCORE>1", + " if (!readtrail)", + " { init_SS((ulong) udmem);", + " } else", + " #endif", + " #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)", + " SS = (uchar *) sh_pre_malloc((ulong) udmem);", + " #else", + " SS = (uchar *) emalloc(udmem);", + " #endif", + " b_store = bstore_mod;", + " } else", + " {", + " #if NCORE>1", + " init_SS(ONE_L<<(ssize-3));", + " #else", + " #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)", + " SS = (uchar *) sh_pre_malloc((ulong)(ONE_L<<(ssize-3)));", + " #else", + " SS = (uchar *) emalloc(ONE_L<<(ssize-3));", + " #endif", + " #endif", + " }", + "}", + "#else", + " #if !defined(MA) || defined(COLLAPSE)", + " void", + " set_H_tab(void)", + " {", + " #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)", + " H_tab = (H_el **) sh_pre_malloc((ulong)((ONE_L<1 && !defined(COLLAPSE)", + " if (!readtrail)", + " { void init_HT(ulong);", + " init_HT(0L);", + " }", + " #endif", + " #endif", + " #endif", + " #if !defined(MA) || defined(COLLAPSE)", + " #if NCORE>1 || (defined(BFS_PAR) && defined(USE_TDH) && !defined(WIN32) && !defined(WIN64))", + " if (!readtrail)", + " { void init_HT(ulong);", + " init_HT((ulong) (ONE_L<= MA)", " { printf(\"pan: error, MA too small, recompile pan.c\");", " printf(\" with -DMA=N with N>%%d\\n\", n);", " Uerror(\"aborting\");", " }", - " if (n > (int) maxgs) maxgs = (unsigned int) n;", - + " if (n > (int) maxgs)", + " { maxgs = (uint) n;", + " }", " for (i = 0; i < n; i++)", - " Info[i] = v[i];", + " { Info[i] = v[i];", + " }", " for ( ; i < MA-1; i++)", - " Info[i] = 0;", + " { Info[i] = 0;", + " }", " Info[MA-1] = pbit;", " if (a_cycles) /* place _a_t at the end */", - " { Info[MA] = Info[0]; Info[0] = 0; }", + " { Info[MA] = Info[0];", + " Info[0] = 0;", + " }", + "", + "#ifdef BFS_PAR", + " e_critical(BFS_STATE); /* bfs_par / g_store */", + "#endif", + "#if NCORE>1 && !defined(SEP_STATE)", + " enter_critical(GLOBAL_LOCK); /* crude, but necessary */", + " /* to make this mode work, also replace emalloc with grab_shared inside store MA routines */", + "#endif", + "", " if (!dfa_store(Info))", " { if (pbit == 0", " && (now._a_t&1)", @@ -4819,16 +7739,17 @@ static char *Code2c[] = { " { Info[MA-1] = 4; /* off-stack bit */", " nShadow++;", " if (!dfa_member(MA-1))", - " {", - "#ifdef VERBOSE", - " printf(\"intersected 1st dfs stack\\n\");", - "#endif", - " return 3;", + " { ret_val = 3;", + " #ifdef VERBOSE", + " printf(\"intersected 1st dfs stack\\n\");", + " #endif", + " goto done;", " } } }", - "#ifdef VERBOSE", + " ret_val = 0;", + " #ifdef VERBOSE", " printf(\"new state\\n\");", - "#endif", - " return 0; /* new state */", + " #endif", + " goto done;", " }", "#ifdef FULLSTACK", " if (pbit == 0)", @@ -4837,23 +7758,32 @@ static char *Code2c[] = { " trpt->proviso = dfa_member(MA-1);", "#endif", " Info[MA-1] = 4; /* off-stack bit */", - " if (dfa_member(MA-1)) {", - "#ifdef VERBOSE", + " if (dfa_member(MA-1))", + " { ret_val = 1; /* off-stack */", + " #ifdef VERBOSE", " printf(\"old state\\n\");", - "#endif", - " return 1; /* off-stack */", - " } else {", - "#ifdef VERBOSE", + " #endif", + " } else", + " { ret_val = 2; /* on-stack */", + " #ifdef VERBOSE", " printf(\"on-stack\\n\");", - "#endif", - " return 2; /* on-stack */", + " #endif", " }", + " goto done;", " }", "#endif", + " ret_val = 1;", "#ifdef VERBOSE", - " printf(\"old state\\n\");", + " printf(\"old state\\n\");", "#endif", - " return 1; /* old state */", + "done:", + "#ifdef BFS_PAR", + " x_critical(BFS_STATE);", + "#endif", + "#if NCORE>1 && !defined(SEP_STATE)", + " leave_critical(GLOBAL_LOCK);", + "#endif", + " return ret_val; /* old state */", "}", "#endif", @@ -4873,34 +7803,140 @@ static char *Code2c[] = { "}", "#endif", - "int", - "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 HC", - " uchar rem_a;", + "#ifdef TRIX", + "void", + "sv_populate(void)", + "{ int i, cnt = 0;", + " TRIX_v6 **base = processes;", + " int bound = now._nr_pr; /* MAXPROC+1; */", + "#ifdef V_TRIX", + " printf(\"%%4d: sv_populate\\n\", depth);", "#endif", - "#ifdef NOCOMP", /* defined by BITSTATE */ - "#if defined(BITSTATE) && defined(LC)", + "again:", + " for (i = 0; i < bound; i++)", + " { if (base[i] != NULL)", + " { H_el *tmp;", + " int m, n; uchar *v;", + "#ifndef BFS", + " if (base[i]->modified == 0)", + " { cnt++;", + " #ifdef V_TRIX", + " printf(\"%%4d: %%s %%d not modified\\n\",", + " depth, (base == processes)?\"proc\":\"chan\", i);", + " #endif", + " continue;", + " }", + " #ifndef V_MOD", + " base[i]->modified = 0;", + " #endif", + "#endif", + "#ifdef TRIX_RIX", + " if (base == processes)", + " { ((P0 *)pptr(i))->_pid = 0;", + " }", + "#endif", + " n = base[i]->psize;", + " v = base[i]->body;", + " s_hash(v, n); /* sets j1_spin */", + " tmp = H_tab[j1_spin];", + " if (!tmp) /* new */", + " { tmp = grab_state(n);", + " H_tab[j1_spin] = tmp;", + " m = 1; /* non-zero */", + " } else", + " { H_el *ntmp, *olst = (H_el *) 0;", + " for (;; hcmp++, olst = tmp, tmp = tmp->nxt)", + " { m = memcmp(((char *)&(tmp->state)), v, n);", + " if (m == 0) /* match */", + " { break;", + " } else if (m < 0) /* insert */", + " { ntmp = grab_state(n);", + " ntmp->nxt = tmp;", + " if (!olst)", + " H_tab[j1_spin] = ntmp;", + " else", + " olst->nxt = ntmp;", + " tmp = ntmp;", + " break;", + " } else if (!tmp->nxt) /* append */", + " { tmp->nxt = grab_state(n);", + " tmp = tmp->nxt;", + " break;", + " } } }", + " if (m != 0)", + " { memcpy((char *)&(tmp->state), v, n);", + "#if defined(AUTO_RESIZE) && !defined(BITSTATE)", + " tmp->m_K1 = K1; /* set via s_hash */", + "#endif", + " if (verbose)", + " { if (base == processes)", + " { _p_count[i]++;", + " } else", + " { _c_count[i]++;", + " } } }", + " now._ids_[cnt++] = (char *)&(tmp->state);", + "#ifdef TRIX_RIX", + " if (base == processes)", + " { ((P0 *)pptr(i))->_pid = i;", + " if (BASE > 0 && i > 0)", + " { ((P0 *)pptr(i))->_pid -= BASE;", + " } }", + "#endif", + " } }", +#if 0 + if a process appears or disappears: always secure a full sv_populate + (channels come and go only with a process) + + only one process can disappear per step + but any nr of channels can be removed at the same time + if a process disappears, all subsequent entries + are then in the wrong place in the _ids_ list + and need to be recomputed + but we do not need to fill out with zeros + because vsize prevents them being used +#endif + " /* do the same for all channels */", + " if (base == processes)", + " { base = channels;", + " bound = now._nr_qs; /* MAXQ+1; */", + " goto again;", + " }", + "}", + "#endif\n", + "#if !defined(BFS_PAR) || (!defined(BITSTATE) && !defined(USE_TDH))", + "int", + "h_store(char *vin, int nin) /* hash table storage */", + "{ H_el *ntmp;", + " H_el *tmp, *olst = (H_el *) 0;", + " char *v; int n, m=0;", + " #ifdef HC", + " uchar rem_a;", + " #endif", + " #ifdef TRIX", + " sv_populate(); /* update proc and chan ids */", + " #endif", + " #ifdef NOCOMP", /* defined by BITSTATE */ + " #if defined(BITSTATE) && defined(LC)", " if (S_Tab == H_tab)", " { v = (char *) &comp_now;", " n = compact_stack(vin, nin);", " } else", " { v = vin; n = nin;", " }", - "#else", + " #else", " v = vin; n = nin;", - "#endif", - "#else", + " #endif", + " #else", " v = (char *) &comp_now;", " #ifdef HC", - " rem_a = now._a_t;", /* 4.3.0 */ + " rem_a = now._a_t;", /* new 5.0 */ " now._a_t = 0;", /* for hashing/state matching to work right */ " #endif", - " n = compress(vin, nin);", /* with HC, this calls s_hash */ + " n = compress(vin, nin);", /* with HC, this calls s_hash -- but on vin, not on v... */ " #ifdef HC", - " now._a_t = rem_a;", /* 4.3.0 */ + " now._a_t = rem_a;", /* new 5.0 */ " #endif", + /* with HC4 -a, compress copies K1 and K2 into v[], leaving v[0] free for the a-bit */ "#ifndef SAFETY", " if (S_A)", " { v[0] = 0; /* _a_t */", @@ -4911,35 +7947,53 @@ static char *Code2c[] = { "#endif", " m = 0;", " }", - "#endif", - "#endif", - "#if !defined(HC) && !(defined(BITSTATE) && defined(LC))", + " #endif", + " #endif", + " #if !defined(HC) && !(defined(BITSTATE) && defined(LC))", " s_hash((uchar *)v, n);", - "#endif", - " tmp = H_tab[j1];", + " #endif", + " /* for BFS_PAR we can only get here in BITSTATE mode */", + " /* and in that case we don't use locks */", + " #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)", + " e_critical(BFS_ID); /* bfs_par / h_store */", + " #endif", + " #if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)", + " enter_critical(CS_ID);", + " #endif", + " tmp = H_tab[j1_spin];", " if (!tmp)", - " { tmp = grab_state(n);", - " H_tab[j1] = tmp;", + " { tmp = grab_state(n);", /* no zero-returns with bfs_par */ + " #if NCORE>1", + " if (!tmp)", + " { /* if we get here -- we've already issued a warning */", + " /* but we want to allow the normal distributed termination */", + " /* to collect the stats on all cpus in the wrapup */", + " #if !defined(SEP_STATE) && !defined(BITSTATE)", + " leave_critical(CS_ID);", + " #endif", + " return 1; /* allow normal termination */", + " }", + " #endif", + " H_tab[j1_spin] = tmp;", " } else", " { for (;; hcmp++, olst = tmp, tmp = tmp->nxt)", " { /* skip the _a_t and the _cnt bytes */", - "#ifdef COLLAPSE", + " #ifdef COLLAPSE", " if (tmp->ln != 0)", " { if (!tmp->nxt) goto Append;", " continue;", " }", - "#endif", + " #endif", " m = memcmp(((char *)&(tmp->state)) + S_A, ", " v + S_A, n - S_A);", " if (m == 0) {", - "#ifdef SAFETY", + " #ifdef SAFETY", "#define wasnew 0", - "#else", + " #else", " int wasnew = 0;", - "#endif", + " #endif", - "#ifndef SAFETY", - "#ifndef NOCOMP", + " #if !defined(SAFETY) && !defined(NOCOMP)", " if (S_A)", " { if ((((char *)&(tmp->state))[0] & V_A) != V_A)", " { wasnew = 1; nShadow++;", @@ -4948,7 +8002,7 @@ static char *Code2c[] = { "#ifndef NOFAIR", " if (S_A > NFAIR)", " { /* 0 <= now._cnt[now._a_t&1] < MAXPROC */", - " unsigned ci, bp; /* index, bit pos */", + " uint ci, bp; /* index, bit pos */", " ci = (now._cnt[now._a_t&1] / 8);", " bp = (now._cnt[now._a_t&1] - 8*ci);", " if (now._a_t&1) /* use tail-bits in _cnt */", @@ -4968,13 +8022,16 @@ static char *Code2c[] = { " /* else: wasnew == 0, i.e., old state */", "#endif", " }", - "#endif", - "#endif", + " #endif", + + " #if NCORE>1", + " Lstate = (H_el *) tmp; /* h_store */", + " #endif", "#ifdef FULLSTACK", "#ifndef SAFETY", /* or else wasnew == 0 */ " if (wasnew)", - " { Lstate = (struct H_el *) tmp;", + " { Lstate = (H_el *) tmp; /* h_store */", " tmp->tagged |= V_A;", " if ((now._a_t&1)", " && (tmp->tagged&A_V)", @@ -4982,22 +8039,42 @@ static char *Code2c[] = { " {", "intersect:", "#ifdef CHECK", + " #if NCORE>1", + " printf(\"cpu%%d: \", core_id);", + " #endif", " printf(\"1st dfs-stack intersected on state %%d+\\n\",", " (int) tmp->st_id);", "#endif", + + " #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)", + " x_critical(BFS_ID);", + " #endif", + " #if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)", + " leave_critical(CS_ID);", + " #endif", + " return 3;", " }", "#ifdef CHECK", + " #if NCORE>1", + " printf(\"cpu%%d: \", core_id);", + " #endif", " printf(\"\tNew state %%d+\\n\", (int) tmp->st_id);", "#endif", "#ifdef DEBUG", " dumpstate(1, (char *)&(tmp->state),n,tmp->tagged);", "#endif", + " #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)", + " x_critical(BFS_ID);", + " #endif", + " #if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)", + " leave_critical(CS_ID);", + " #endif", " return 0;", " } else", "#endif", " if ((S_A)?(tmp->tagged&V_A):tmp->tagged)", - " { Lstate = (struct H_el *) tmp;", + " { Lstate = (H_el *) tmp; /* h_store */", "#ifndef SAFETY", " /* already on current dfs stack */", " /* but may also be on 1st dfs stack */", @@ -5014,41 +8091,110 @@ static char *Code2c[] = { " goto intersect;", "#endif", "#ifdef CHECK", + " #if NCORE>1", + " printf(\"cpu%%d: \", core_id);", + " #endif", " printf(\"\tStack state %%d\\n\", (int) tmp->st_id);", "#endif", "#ifdef DEBUG", " dumpstate(0, (char *)&(tmp->state),n,tmp->tagged);", "#endif", + " #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)", + " x_critical(BFS_ID);", + " #endif", + " #if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)", + " leave_critical(CS_ID);", + " #endif", " return 2; /* match on stack */", " }", "#else", " if (wasnew)", " {", "#ifdef CHECK", + " #if NCORE>1", + " printf(\"cpu%%d: \", core_id);", + " #endif", " printf(\"\tNew state %%d+\\n\", (int) tmp->st_id);", "#endif", "#ifdef DEBUG", " dumpstate(1, (char *)&(tmp->state), n, 0);", "#endif", + " #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)", + " x_critical(BFS_ID);", + " #endif", + " #if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)", + " leave_critical(CS_ID);", + " #endif", " return 0;", " }", "#endif", "#ifdef CHECK", + "#if NCORE>1", + " printf(\"cpu%%d: \", core_id);", + "#endif", " printf(\"\tOld state %%d\\n\", (int) tmp->st_id);", "#endif", "#ifdef DEBUG", " dumpstate(0, (char *)&(tmp->state), n, 0);", "#endif", - "#ifdef REACH", - " if (tmp->D > depth)", - " { tmp->D = depth;", - "#ifdef CHECK", - " printf(\"\t\tReVisiting (from smaller depth)\\n\");", - "#endif", - " nstates--;", + "#if defined(BCS)", + " #ifdef CONSERVATIVE", + " if (tmp->ctx_low > trpt->sched_limit)", + " { tmp->ctx_low = trpt->sched_limit;", + " tmp->ctx_pid[(now._last)/8] = 1 << ((now._last)%%8); /* new */", + " #ifdef CHECK", + " #if NCORE>1", + " printf(\"cpu%%d: \", core_id);", + " #endif", + " printf(\"\t\tRevisit with fewer context switches\\n\");", + " #endif", + " nstates--;", + " #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)", + " x_critical(BFS_ID);", + " #endif", + " #if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)", + " leave_critical(CS_ID);", + " #endif", + " return 0;", + " } else if ((tmp->ctx_low == trpt->sched_limit", + " && (tmp->ctx_pid[(now._last)/8] & ( 1 << ((now._last)%%8) )) == 0 ))", + " { tmp->ctx_pid[(now._last)/8] |= 1 << ((now._last)%%8); /* add */", + " #ifdef CHECK", + " #if NCORE>1", + " printf(\"cpu%%d: \", core_id);", + " #endif", + " printf(\"\t\tRevisit with same nr of context switches\\n\");", + " #endif", + " nstates--;", + " #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)", + " x_critical(BFS_ID);", + " #endif", + " #if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)", + " leave_critical(CS_ID);", + " #endif", + " return 0;", + " }", + " #endif", + "#endif", + " #ifdef REACH", + " if (tmp->D > depth)", + " { tmp->D = depth;", + " #ifdef CHECK", + " #if NCORE>1", + " printf(\"cpu%%d: \", core_id);", + " #endif", + " printf(\"\t\tReVisiting (from smaller depth)\\n\");", + " #endif", + " nstates--;", + " #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)", + " x_critical(BFS_ID);", + " #endif", + " #if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)", + " leave_critical(CS_ID);", + " #endif", #if 0 - possible variation of iterative search for shortest counter-example (pan -i - and pan -I) suggested by Pierre Moro (for safety properties): + a 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 @@ -5056,54 +8202,86 @@ static char *Code2c[] = { 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 */ + shortest counter-example - so not enabled by default) + " if (errors > 0 && iterative)", /* Moro */ #endif - " return 0;", - " }", - "#endif", - "#if defined(BFS) && defined(Q_PROVISO)", - " Lstate = (struct H_el *) tmp;", - "#endif", + " return 0;", + " }", + " #endif", + " #if (defined(BFS) && defined(Q_PROVISO)) || NCORE>1", + " Lstate = (H_el *) tmp; /* h_store */", + " #endif", + " #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)", + " x_critical(BFS_ID);", + " #endif", + " #if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)", + " leave_critical(CS_ID);", + " #endif", " return 1; /* match outside stack */", " } else if (m < 0)", " { /* insert state before tmp */", " ntmp = grab_state(n);", + " #if NCORE>1", + " if (!ntmp)", + " {", + " #if !defined(SEP_STATE) && !defined(BITSTATE)", + " leave_critical(CS_ID);", + " #endif", + " return 1; /* allow normal termination */", + " }", + " #endif", " ntmp->nxt = tmp;", " if (!olst)", - " H_tab[j1] = ntmp;", + " H_tab[j1_spin] = ntmp;", " else", " olst->nxt = ntmp;", " tmp = ntmp;", " break;", " } else if (!tmp->nxt)", " { /* append after tmp */", - "#ifdef COLLAPSE", + " #ifdef COLLAPSE", "Append:", - "#endif", + " #endif", " tmp->nxt = grab_state(n);", + " #if NCORE>1", + " if (!tmp->nxt)", + " {", + " #if !defined(SEP_STATE) && !defined(BITSTATE)", + " leave_critical(CS_ID);", + " #endif", + " return 1; /* allow normal termination */", + " }", + " #endif", " tmp = tmp->nxt;", " break;", " } }", " }", - "#ifdef CHECK", + " #ifdef CHECK", " tmp->st_id = (unsigned) nstates;", + " #if NCORE>1", + " printf(\"cpu%%d: \", core_id);", + " #endif", "#ifdef BITSTATE", " printf(\" Push state %%d\\n\", ((int) nstates) - 1);", "#else", " printf(\" New state %%d\\n\", (int) nstates);", "#endif", "#endif", - "#if !defined(SAFETY) || defined(REACH)", + " #if defined(BCS)", + " tmp->ctx_low = trpt->sched_limit;", + " #ifdef CONSERVATIVE", + " tmp->ctx_pid[(now._last)/8] = 1 << ((now._last)%%8); /* new limit */", + " #endif", + " #endif", + " #if !defined(SAFETY) || defined(REACH)", " tmp->D = depth;", - "#endif", - "#ifndef SAFETY", - "#ifndef NOCOMP", + " #endif", + " #if !defined(SAFETY) && !defined(NOCOMP)", " if (S_A)", " { v[0] = V_A;", "#ifndef NOFAIR", " if (S_A > NFAIR)", - " { unsigned ci, bp; /* as above */", + " { uint ci, bp; /* as above */", " ci = (now._cnt[now._a_t&1] / 8);", " bp = (now._cnt[now._a_t&1] - 8*ci);", " if (now._a_t&1)", @@ -5114,26 +8292,409 @@ static char *Code2c[] = { " }", "#endif", " }", - "#endif", - "#endif", + " #endif", + " #if defined(AUTO_RESIZE) && !defined(BITSTATE)", + " tmp->m_K1 = K1;", + " #endif", " memcpy(((char *)&(tmp->state)), v, n);", - "#ifdef FULLSTACK", + " #ifdef FULLSTACK", " tmp->tagged = (S_A)?V_A:(depth+1);", "#ifdef DEBUG", - " dumpstate(-1, v, n, tmp->tagged);", + " dumpstate(-1, v, n, tmp->tagged);", "#endif", - " Lstate = (struct H_el *) tmp;", - "#else", - "#ifdef DEBUG", - " dumpstate(-1, v, n, 0);", - "#endif", - "#endif", + " Lstate = (H_el *) tmp; /* end of h_store */", + " #else", + " #ifdef DEBUG", + " dumpstate(-1, v, n, 0);", + " #endif", + " #if NCORE>1", + " Lstate = (H_el *) tmp; /* end of h_store */", + " #endif", + " #endif", + + " #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)", + " x_critical(BFS_ID);", + " #endif", + " #if NCORE>1", + " #ifdef V_PROVISO", + " tmp->cpu_id = core_id;", + " #endif", + " #if !defined(SEP_STATE) && !defined(BITSTATE)", + " leave_critical(CS_ID);", + " #endif", + " #endif", + " return 0;", + "}", /* end of h_store */ + "#endif", /* !BFS_PAR || !USE_TDH */ + "", + "void", + "o_hash32(uchar *s, int len, int h) /* 32-bit, like d_sfh, but with seed */", + "{ uint32_t tmp;", + " int rem;", + "", + " rem = len & 3;", + " len >>= 2;", + "", + " for ( ; len > 0; len--)", + " { h += get16bits(s);", + " tmp = (get16bits(s+2) << 11) ^ h;", + " h = (h << 16) ^ tmp;", + " s += 2*sizeof(uint16_t);", + " h += h >> 11;", + " }", + " switch (rem) {", + " case 3: h += get16bits(s);", + " h ^= h << 16;", + " h ^= s[sizeof(uint16_t)] << 18;", + " h += h >> 11;", + " break;", + " case 2: h += get16bits(s);", + " h ^= h << 11;", + " h += h >> 17;", + " break;", + " case 1: h += *s;", + " h ^= h << 10;", + " h += h >> 1;", + " break;", + " }", + " h ^= h << 3;", + " h += h >> 5;", + " h ^= h << 4;", + " h += h >> 17;", + " h ^= h << 25;", + " h += h >> 6;", + "", + " K1 = h;", + "}", + "void", + "o_hash64(uchar *kb, int nbytes, int seed)", /* 64-bit hash */ + "{ uint8_t *bp;", + " uint64_t a, b, c, n;", + " const uint64_t *k = (uint64_t *) kb;", + " n = nbytes/WS; /* nr of 8-byte chunks */", + " /* extend to multiple of words, if needed */", + " a = WS - (nbytes %% WS);", + " if (a > 0 && a < WS)", + " { n++;", + " bp = kb + nbytes;", + " switch (a) {", + " case 7: *bp++ = 0; /* fall thru */", + " case 6: *bp++ = 0; /* fall thru */", + " case 5: *bp++ = 0; /* fall thru */", + " case 4: *bp++ = 0; /* fall thru */", + " case 3: *bp++ = 0; /* fall thru */", + " case 2: *bp++ = 0; /* fall thru */", + " case 1: *bp = 0;", + " case 0: break;", + " } }", + " a = (uint64_t) seed;", + " b = HASH_CONST[HASH_NR];", + " c = 0x9e3779b97f4a7c13LL; /* arbitrary */", + " while (n >= 3)", + " { a += k[0];", + " b += k[1];", + " c += k[2];", + " mix(a,b,c);", + " n -= 3;", + " k += 3;", + " }", + " c += (((uint64_t) nbytes)<<3);", + " switch (n) {", + " case 2: b += k[1];", + " case 1: a += k[0];", + " case 0: break;", + " }", + " mix(a,b,c);", + "", + " K1 = a;", + "}", + "", + "#if defined(USE_TDH) && !defined(WIN32) && !defined(WIN64)", +#if 0 + some problems with this storage mode: + + 0. pre-allocates full hash-table with slots equal to max statevector size + e.g. with -w26 we allocate 2^26 (64 M) slots of VECTORSZ large + which can accomodate up to 64 M states + once you get close to or exceed the max, the search aborts + with a 'hashtable full' message + in HC mode the max storage needed per state is more modest and independent + of the maximum vectorsize; which makes this mode attractive as a default + + 1. does not support PO reduction through the Lstate->ostate->tagged + to distinguish open from closed states - this can reduce states by 50% + could add this as another bit from the hash value + e.g., could add it in HC mode to the first hash? + + 2. the same state may be stored multiple times +#endif + "#ifdef HC", + " #ifndef T_HC", + " #ifdef BFS_HC", + " #define T_HC BFS_HC", + " #else", + " #define T_HC 2", + " #endif", + " #endif", + " #if T_HC<1 || T_HC>4", + " #error \"BFS_HC must be 1, 2, 3, or 4 (default is 2)\"", + " #endif", + "#endif", + "", + "#define T_ROW 6", /* related to cache line size */ + "#define T_ROW_SIZE (1< x))", + " { Uerror(\"assertion x * (ulong) T_VSZ > x fails\");", + " }", + " #ifdef BFS_SEP_HASH", + " ohash_sd = (char *) emalloc(x * (ulong) T_VSZ);", + " #else", + " ohash_sd = (volatile char *) sh_pre_malloc(x * (ulong) T_VSZ);", + " #endif", + "#else", /* assume T_HC >= 1, and normally 2 */ + " ohash_hc_sz = (ulong) (T_HC * (ulong) sizeof(uint32_t));", + " if (!(x * ohash_hc_sz > x))", /* watch for overflow */ + " { Uerror(\"assertion x * ohash_hc_sz > x fails\");", + " }", + " #ifdef BFS_SEP_HASH", + " ohash_sd = (char *) emalloc(x * ohash_hc_sz);", + " #else", + " ohash_sd = (volatile char *) sh_pre_malloc(x * ohash_hc_sz);", + " #endif", + "#endif", + "#ifdef BFS_SEP_HASH", + " ohash_hv = (uint32_t *) emalloc(x * (ulong) sizeof(uint32_t));", + "#else", + " ohash_hv = (volatile uint32_t *) sh_pre_malloc(x * (ulong) sizeof(uint32_t));", + "#endif", + " ohash_mask = (((ulong)1)<o_pm &= ~2;", + "#ifdef VERBOSE", + " bfs_printf(\"check to mark\\n\");", + "#endif", + " for (i = 0; i < (int) now._nr_pr; i++)", + " { P0 *ptr = (P0 *) pptr(i);", + " if (accpstate[ptr->_t][ptr->_p])", + " { trpt->o_pm |= 2;", + " now._l_bnd = L_bound;", + " now._l_sds = (uchar *) 0;", + "#ifdef VERBOSE", + " bfs_printf(\"mark state live\\n\");", + "#endif", + " break;", + " } }", + "}", + "void", + "bfs_check_live(uchar b, uchar *s)", + "{ /* assert(b>0); */", + " now._l_bnd = b-1; /* decrease bound */", + "#ifdef VERBOSE", + " bfs_printf(\"check live %%d\\n\", b);", + "#endif", + " if (b == L_bound && boq == -1)", /* never mid rv */ + " { now._l_sds = (uchar *) Lstate; /* new target */", + " } else", + " { now._l_sds = s; /* restore target */", + " if (s == (uchar *) Lstate)", + " { depthfound = depth - (BASE+1)*(L_bound - now._l_bnd - 1);", + " uerror(\"accept cycle found\");", + " depthfound = -1;", + " now._l_bnd = 0;", + " now._l_sds = (uchar *) 0;", + " } }", + "#ifdef VERBOSE", + " bfs_printf(\"set l_bound to %%d -- sds %%p\\n\", b-1, (void *) now._l_sds);", + "#endif", "}", "#endif", + "/* closed hashing with locality - similar to ltsmin */", + "int", + "o_store(const char *vin, int nin)", + "{ int i, seed = 0;", + " ulong hash_v, ix, ex;", + " uint32_t T_BUSY, T_DONE;", + " volatile uint32_t *t_entry;", + "#ifdef HC", + " ulong vs = ohash_hc_sz;", + "#else", + " ulong vs = (ulong) T_VSZ;", + "#endif", + "#ifdef L_BOUND", + " uchar o_bnd, *o_sds;", + "#endif", + "#ifndef STOP_ON_FULL", + " if (h_table_full)", + " { goto done;", + " }", + "#endif", + "#ifdef L_BOUND", + " if (now._l_bnd == 0)", + " { bfs_mark_live();", + " }", + " #ifdef VERBOSE", + " else", + " { bfs_printf(\"non-markable state %%d\\n\", now._l_bnd);", + " }", + " #endif", + " o_bnd = now._l_bnd;", + " o_sds = now._l_sds;", + " now._l_bnd = (o_bnd)?1:0; /* mark nested phase of bounded search */", + " now._l_sds = (uchar *) 0;", + "#endif", + "#if !defined(HC) && !defined(T_NOCOMP)", + " nin = compress((char *)vin, nin);", + " vin = (char *) &comp_now;", + "#endif", + " do { o_hash((uchar *)vin, nin, seed++);", + " hash_v = K1;", + " } while (hash_v == T_FREE || hash_v == T_STAT); /* unlikely, hash_v 0 or 1 */", + "", + " T_BUSY = ((uint32_t) hash_v & ~((uint32_t) T_STAT)); /* hash with status bit 0 */", + " T_DONE = ((uint32_t) hash_v | ((uint32_t) T_STAT)); /* hash with status bit 1 */", + "#ifdef HC", + " d_hash((uchar *)vin, nin);", /* HC */ + " ohash_hc[0] = (uint32_t) K1;", + " #if T_HC>1", + " ohash_hc[1] = (uint32_t) (K1>>32);", /* assumes ulong = 64 bits */ + " #endif", + " #if T_HC>2", + " ohash_hc[2] = (uint32_t) K2;", + " #endif", + " #if T_HC>3", + " ohash_hc[3] = (uint32_t) (K2>>32);", + " #endif", + "#endif", + " while (seed < ohash_max)", + " { ix = hash_v & ohash_mask;", + " ex = (ix & T_ROW_MASK) + T_ROW_SIZE;", + " for (i = 0; i < T_ROW_SIZE; i++)", + " { t_entry = (uint32_t *) &ohash_hv[ix];", + " if (*t_entry == T_FREE && cas(t_entry, T_FREE, T_BUSY))", + " {", + "#ifndef HC", + " memcpy((char *) &ohash_sd[ix * vs], vin, nin);", + "#else", + " memcpy((char *) &ohash_sd[ix * vs], (char *) ohash_hc, vs);", + "#endif", + "#if defined(USE_TDH) && defined(Q_PROVISO)", + " ohash_inq[ix] = (uchar) BFS_INQ;", + " Lstate = (H_el *) &ohash_inq[ix];", + "#endif", + " *t_entry = T_DONE;", + "#ifdef VERBOSE", + " #ifdef L_BOUND", + " bfs_printf(\"New state %%p [%%p]\\n\",", + " (void *) Lstate, (void *) o_sds);", + " #else", + " bfs_printf(\"New state %%p\\n\", (void *) Lstate);", + " #endif", + "#endif", + "#ifdef L_BOUND", + " if (o_bnd) { bfs_check_live(o_bnd, o_sds); }", + "#endif", + " return 0; /* New State */", + " }", + " while (*t_entry == T_BUSY)", + " { usleep(2); /* wait */", + " }", + " if (*t_entry == T_DONE /* (first) hash matches, check data */", + "#ifndef HC", + " && memcmp((char *) &ohash_sd[ix * vs], vin, nin) == 0)", + "#else", + " && memcmp((char *) &ohash_sd[ix * vs], (char *) ohash_hc, vs) == 0)", + "#endif", + " {", + "#if defined(USE_TDH) && defined(Q_PROVISO)", + " Lstate = (H_el *) &ohash_inq[ix];", + "#endif", + "#ifdef VERBOSE", + " #ifdef L_BOUND", + " bfs_printf(\"Old state %%p [%%p]\\n\",", + " (void *) Lstate, (void *) o_sds);", + " #else", + " bfs_printf(\"Old state %%p\\n\", (void *) Lstate);", + " #endif", + "#endif", + "#ifdef L_BOUND", + " if (o_bnd) { bfs_check_live(o_bnd, o_sds); }", + "#endif", + " return 1; /* Old State */", + " }", + " hcmp++; ix++;", + " ix = (ix==ex) ? ex - T_ROW_SIZE : ix;", + " }", + " /* find a new slot: */", + " do { o_hash((uchar *)vin, nin, (int) (hash_v + seed++));", + " hash_v = K1;", + " } while (hash_v == T_FREE || hash_v == T_STAT);", + " T_BUSY = ((uint32_t) hash_v & ~((uint32_t) T_STAT));", + " T_DONE = ((uint32_t) hash_v | ((uint32_t) T_STAT));", + " }", + "#ifdef STOP_ON_FULL", + " Uerror(\"hash table full\");", + " /* no return from Uerror */", + "#else", + " if (!h_table_full)", + " { h_table_full++;", + " if (who_am_i == 0)", + " { bfs_printf(\"hash table is full\\n\");", + " } }", + "done:", + " bfs_punt++; /* counts this as a lost state */", + "#endif", + "#ifdef L_BOUND", + " now._l_bnd = 0; /* no more checking */", + " now._l_sds = (uchar *) 0;", + "#endif", + " return 1; /* technically should be 0, but we want to throttle down */", + "}", + "#endif", /* USE_TDH && !WIN32 && !WIN64 */ + "#endif", /* !BITSTATE || FULLSTACK */ "#include TRANSITIONS", - "void", - "do_reach(void)", - "{", 0, }; diff --git a/sys/src/cmd/spin/pangen2.c b/sys/src/cmd/spin/pangen2.c index 05ad9fa1f..828ded881 100644 --- a/sys/src/cmd/spin/pangen2.c +++ b/sys/src/cmd/spin/pangen2.c @@ -1,13 +1,10 @@ /***** spin: pangen2.c *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #include "spin.h" #include "version.h" @@ -15,33 +12,40 @@ #include "pangen2.h" #include "pangen4.h" #include "pangen5.h" +#include "pangen7.h" #define DELTA 500 /* sets an upperbound on nr of chan names */ #define blurb(fd, e) { fprintf(fd, "\n"); if (!merger) fprintf(fd, "\t\t/* %s:%d */\n", \ e->n->fn->name, e->n->ln); } -#define tr_map(m, e) { if (!merger) fprintf(tt, "\t\ttr_2_src(%d, %s, %d);\n", \ +#define tr_map(m, e) { if (!merger) fprintf(tt, "\t\ttr_2_src(%d, \"%s\", %d);\n", \ m, e->n->fn->name, e->n->ln); } extern ProcList *rdy; extern RunList *run; +extern Lextok *runstmnts; extern Symbol *Fname, *oFname, *context; extern char *claimproc, *eventmap; -extern int lineno, verbose, Npars, Mpars; +extern int lineno, verbose, Npars, Mpars, nclaims; 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 Ntimeouts, Etimeouts, deadvar, old_scope_rules, old_priority_rules; +extern int u_sync, u_async, nrRdy, Unique; extern int GenCode, IsGuard, Level, TestOnly; +extern int globmin, globmax, ltl_mode, dont_simplify; + extern short has_stack; -extern char *NextLab[]; +extern char *NextLab[64]; /* must match value in dstep.c:18 */ -FILE *tc, *th, *tt, *tm, *tb; +int buzzed; +FILE *tc, *th, *tt, *tb; +static FILE *tm; -int OkBreak = -1; +int OkBreak = -1, has_hidden = 0; /* has_hidden set in sym.c and structs.c */ short nocast=0; /* to turn off casts in lvalues */ short terse=0; /* terse printing of varnames */ short no_arrays=0; short has_last=0; /* spec refers to _last */ +short has_priority=0; /* spec refers to _priority */ short has_badelse=0; /* spec contains else combined with chan refs */ short has_enabled=0; /* spec contains enabled() */ short has_pcvalue=0; /* spec contains pc_value() */ @@ -52,9 +56,7 @@ 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 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 */ +short has_ltl=0; /* has inline ltl formulae */ int mst=0; /* max nr of state/process */ int claimnr = -1; /* claim process, if any */ int eventmapnr = -1; /* event trace, if any */ @@ -74,6 +76,9 @@ static int TPE[2], EPT[2]; static int uniq=1; static int multi_needed, multi_undo; static short AllGlobal=0; /* set if process has provided clause */ +static short withprocname=0; /* prefix local varnames with procname */ +static short _isok=0; /* checks usage of predefined variable _ */ +static short evalindex=0; /* evaluate index of var names */ int has_global(Lextok *); static int getweight(Lextok *); @@ -86,6 +91,29 @@ static void putproc(ProcList *); static void Tpe(Lextok *); extern void spit_recvs(FILE *, FILE*); +static L_List *keep_track; + +void +keep_track_off(Lextok *n) +{ L_List *p; + + p = (L_List *) emalloc(sizeof(L_List)); + p->n = n; + p->nxt = keep_track; + keep_track = p; +} + +int +check_track(Lextok *n) +{ L_List *p; + + for (p = keep_track; p; p = p->nxt) + { if (p->n == n) + { return n->sym?n->sym->type:0; + } } + return 0; +} + static int fproc(char *s) { ProcList *p; @@ -98,12 +126,33 @@ fproc(char *s) return -1; } +int +pid_is_claim(int p) /* Pid (p->tn) to type (p->b) */ +{ ProcList *r; + + for (r = rdy; r; r = r->nxt) + { if (r->tn == p) return (r->b == N_CLAIM); + } + printf("spin: error, cannot find pid %d\n", p); + return 0; +} + static void reverse_procs(RunList *q) { if (!q) return; reverse_procs(q->nxt); - fprintf(tc, " Addproc(%d);\n", q->tn); + fprintf(tc, " Addproc(%d, %d);\n", + q->tn, q->priority < 1 ? 1 : q->priority); +} + +static void +forward_procs(RunList *q) +{ + if (!q) return; + fprintf(tc, " Addproc(%d, %d);\n", + q->tn, q->priority < 1 ? 1 : q->priority); + forward_procs(q->nxt); } static void @@ -111,13 +160,14 @@ tm_predef_np(void) { fprintf(th, "#define _T5 %d\n", uniq++); fprintf(th, "#define _T2 %d\n", uniq++); + fprintf(tm, "\tcase _T5:\t/* np_ */\n"); if (separate == 2) - fprintf(tm, "\t\tif (!((!(o_pm&4) && !(tau&128))))\n"); - else - fprintf(tm, "\t\tif (!((!(trpt->o_pm&4) && !(trpt->tau&128))))\n"); - + { fprintf(tm, "\t\tif (!((!(o_pm&4) && !(tau&128))))\n"); + } else + { fprintf(tm, "\t\tif (!((!(trpt->o_pm&4) && !(trpt->tau&128))))\n"); + } fprintf(tm, "\t\t\tcontinue;\n"); fprintf(tm, "\t\t/* else fall through */\n"); fprintf(tm, "\tcase _T2:\t/* true */\n"); @@ -151,51 +201,120 @@ static struct { void gensrc(void) { ProcList *p; + int i; - if (!(tc = fopen(Cfile[0].nm[separate], "w")) /* main routines */ - || !(th = fopen(Cfile[1].nm[separate], "w")) /* header file */ - || !(tt = fopen(Cfile[2].nm[separate], "w")) /* transition matrix */ - || !(tm = fopen(Cfile[3].nm[separate], "w")) /* forward moves */ - || !(tb = fopen(Cfile[4].nm[separate], "w"))) /* backward moves */ + disambiguate(); /* avoid name-clashes between scopes */ + + if (!(tc = fopen(Cfile[0].nm[separate], MFLAGS)) /* main routines */ + || !(th = fopen(Cfile[1].nm[separate], MFLAGS)) /* header file */ + || !(tt = fopen(Cfile[2].nm[separate], MFLAGS)) /* transition matrix */ + || !(tm = fopen(Cfile[3].nm[separate], MFLAGS)) /* forward moves */ + || !(tb = fopen(Cfile[4].nm[separate], MFLAGS))) /* backward moves */ { 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, "#ifndef PAN_H\n"); + fprintf(th, "#define PAN_H\n\n"); + + fprintf(th, "#define SpinVersion \"%s\"\n", SpinVersion); + fprintf(th, "#define PanSource \""); + for (i = 0; oFname->name[i] != '\0'; i++) + { char c = oFname->name[i]; + if (c == '\\' || c == ' ') /* Windows path */ + { fprintf(th, "\\"); + } + fprintf(th, "%c", c); + } + fprintf(th, "\"\n\n"); + + fprintf(th, "#define G_long %d\n", (int) sizeof(long)); + fprintf(th, "#define G_int %d\n\n", (int) sizeof(int)); + fprintf(th, "#define ulong unsigned long\n"); + fprintf(th, "#define ushort unsigned short\n"); + + fprintf(th, "#ifdef WIN64\n"); + fprintf(th, " #define ONE_L (1L)\n"); + fprintf(th, "/* #define long long long */\n"); + fprintf(th, "#else\n"); + fprintf(th, " #define ONE_L (1L)\n"); + fprintf(th, "#endif\n\n"); + + fprintf(th, "#ifdef BFS_PAR\n"); + fprintf(th, " #define NRUNS %d\n", (runstmnts)?1:0); + fprintf(th, " #ifndef BFS\n"); + fprintf(th, " #define BFS\n"); + fprintf(th, " #endif\n"); + fprintf(th, " #ifndef PUTPID\n"); + fprintf(th, " #define PUTPID\n"); + fprintf(th, " #endif\n\n"); + fprintf(th, " #if !defined(USE_TDH) && !defined(NO_TDH)\n"); + fprintf(th, " #define USE_TDH\n"); + fprintf(th, " #endif\n"); + fprintf(th, " #if defined(USE_TDH) && !defined(NO_HC)\n"); + fprintf(th, " #define HC /* default for USE_TDH */\n"); + fprintf(th, " #endif\n"); + fprintf(th, " #ifndef BFS_MAXPROCS\n"); + fprintf(th, " #define BFS_MAXPROCS 64 /* max nr of cores to use */\n"); + fprintf(th, " #endif\n"); + + fprintf(th, " #define BFS_GLOB 0 /* global lock */\n"); + fprintf(th, " #define BFS_ORD 1 /* used with -DCOLLAPSE */\n"); + fprintf(th, " #define BFS_MEM 2 /* malloc from shared heap */\n"); + fprintf(th, " #define BFS_PRINT 3 /* protect printfs */\n"); + fprintf(th, " #define BFS_STATE 4 /* hashtable */\n\n"); + fprintf(th, " #define BFS_INQ 2 /* state is in q */\n\n"); + + fprintf(th, " #ifdef BFS_FIFO\n"); /* queue access */ + fprintf(th, " #define BFS_ID(a,b) (BFS_STATE + (int) ((a)*BFS_MAXPROCS+(b)))\n"); + fprintf(th, " #define BFS_MAXLOCKS (BFS_STATE + (BFS_MAXPROCS*BFS_MAXPROCS))\n"); + fprintf(th, " #else\n"); /* h_store access (not needed for o_store) */ + fprintf(th, " #ifndef BFS_W\n"); + fprintf(th, " #define BFS_W 10\n"); /* 1< 4) /* 64 bit machine */ - { fprintf(th, "#ifndef HASH32\n"); - fprintf(th, "#define HASH64\n"); - fprintf(th, "#endif\n"); - } -#if 0 - if (sizeof(long)==sizeof(int)) - fprintf(th, "#define long int\n"); -#endif if (separate == 1 && !claimproc) { Symbol *n = (Symbol *) emalloc(sizeof(Symbol)); Sequence *s = (Sequence *) emalloc(sizeof(Sequence)); + s->minel = -1; claimproc = n->name = "_:never_template:_"; - ready(n, ZN, s, 0, ZN); + ready(n, ZN, s, 0, ZN, N_CLAIM); } if (separate == 2) { if (has_remote) @@ -207,20 +326,29 @@ gensrc(void) fprintf(th, "#endif\n"); if (has_last) fprintf(th, "#define HAS_LAST %d\n", has_last); + if (has_priority && !old_priority_rules) + fprintf(th, "#define HAS_PRIORITY %d\n", has_priority); goto doless; } fprintf(th, "#define DELTA %d\n", DELTA); fprintf(th, "#ifdef MA\n"); - fprintf(th, "#if MA==1\n"); /* user typed -DMA without size */ - fprintf(th, "#undef MA\n#define MA 100\n"); - fprintf(th, "#endif\n#endif\n"); + fprintf(th, " #if NCORE>1 && !defined(SEP_STATE)\n"); + fprintf(th, " #define SEP_STATE\n"); + fprintf(th, " #endif\n"); + fprintf(th, " #if MA==1\n"); /* user typed -DMA without size */ + fprintf(th, " #undef MA\n"); + fprintf(th, " #define MA 100\n"); + fprintf(th, " #endif\n"); + fprintf(th, "#endif\n"); fprintf(th, "#ifdef W_XPT\n"); - fprintf(th, "#if W_XPT==1\n"); /* user typed -DW_XPT without size */ - fprintf(th, "#undef W_XPT\n#define W_XPT 1000000\n"); - fprintf(th, "#endif\n#endif\n"); + fprintf(th, " #if W_XPT==1\n"); /* user typed -DW_XPT without size */ + fprintf(th, " #undef W_XPT\n"); + fprintf(th, " #define W_XPT 1000000\n"); + fprintf(th, " #endif\n"); + fprintf(th, "#endif\n"); fprintf(th, "#ifndef NFAIR\n"); - fprintf(th, "#define NFAIR 2 /* must be >= 2 */\n"); + fprintf(th, " #define NFAIR 2 /* must be >= 2 */\n"); fprintf(th, "#endif\n"); if (Ntimeouts) fprintf(th, "#define NTIM %d\n", Ntimeouts); @@ -230,18 +358,33 @@ gensrc(void) fprintf(th, "#define REM_VARS 1\n"); if (has_remote) fprintf(th, "#define REM_REFS %d\n", has_remote); /* not yet used */ + if (has_hidden) + { fprintf(th, "#define HAS_HIDDEN %d\n", has_hidden); + fprintf(th, "#if defined(BFS_PAR) || defined(BFS)\n"); + fprintf(th, " #error cannot use BFS on models with variables declared hidden\n"); + fprintf(th, "#endif\n"); + } if (has_last) fprintf(th, "#define HAS_LAST %d\n", has_last); + if (has_priority && !old_priority_rules) + fprintf(th, "#define HAS_PRIORITY %d\n", has_priority); 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); - fprintf(th, "#define HAS_CODE\n"); /* doesn't seem to cause measurable overhead */ + if (has_ltl) + fprintf(th, "#define HAS_LTL 1\n"); + fprintf(th, "#define HAS_CODE 1\n"); /* could also be set to has_code */ + /* always defining it doesn't seem to cause measurable overhead though */ + /* and allows for pan -r etc to work for non-embedded code as well */ + fprintf(th, "#if defined(RANDSTORE) && !defined(RANDSTOR)\n"); + fprintf(th, " #define RANDSTOR RANDSTORE\n"); /* xspin uses RANDSTORE... */ + fprintf(th, "#endif\n"); if (has_stack) - fprintf(th, "#define HAS_STACK\n"); - if (has_enabled) + fprintf(th, "#define HAS_STACK %d\n", has_stack); + if (has_enabled || (has_priority && !old_priority_rules)) fprintf(th, "#define HAS_ENABLED 1\n"); if (has_unless) fprintf(th, "#define HAS_UNLESS %d\n", has_unless); @@ -252,11 +395,12 @@ gensrc(void) if (has_badelse) fprintf(th, "#define HAS_BADELSE %d\n", has_badelse); if (has_enabled + || (has_priority && !old_priority_rules) || has_pcvalue || has_badelse || has_last) { fprintf(th, "#ifndef NOREDUCE\n"); - fprintf(th, "#define NOREDUCE 1\n"); + fprintf(th, " #define NOREDUCE 1\n"); fprintf(th, "#endif\n"); } if (has_np) @@ -265,33 +409,46 @@ gensrc(void) fprintf(th, "#define MERGED 1\n"); doless: - fprintf(th, "#ifdef NP /* includes np_ demon */\n"); + fprintf(th, "#if !defined(HAS_LAST) && defined(BCS)\n"); + fprintf(th, " #define HAS_LAST 1 /* use it, but */\n"); + fprintf(th, " #ifndef STORE_LAST\n"); /* unless the user insists */ + fprintf(th, " #define NO_LAST 1 /* dont store it */\n"); + fprintf(th, " #endif\n"); + fprintf(th, "#endif\n"); + + fprintf(th, "#if defined(BCS) && defined(BITSTATE)\n"); + fprintf(th, " #ifndef NO_CTX\n"); + fprintf(th, " #define STORE_CTX 1\n"); + fprintf(th, " #endif\n"); + fprintf(th, "#endif\n"); + + fprintf(th, "#ifdef NP\n"); if (!has_np) - fprintf(th, "#define HAS_NP 2\n"); - fprintf(th, "#define VERI %d\n", nrRdy); - fprintf(th, "#define endclaim 3 /* none */\n"); + fprintf(th, " #define HAS_NP 2\n"); + fprintf(th, " #define VERI %d /* np_ */\n", nrRdy); fprintf(th, "#endif\n"); if (claimproc) - { claimnr = fproc(claimproc); - /* NP overrides claimproc */ - fprintf(th, "#if !defined(NOCLAIM) && !defined NP\n"); - fprintf(th, "#define VERI %d\n", claimnr); - fprintf(th, "#define endclaim endstate%d\n", claimnr); + { claimnr = fproc(claimproc); /* the default claim */ + fprintf(th, "#ifndef NOCLAIM\n"); + fprintf(th, " #define NCLAIMS %d\n", nclaims); + fprintf(th, " #ifndef NP\n"); + fprintf(th, " #define VERI %d\n", claimnr); + fprintf(th, " #endif\n"); fprintf(th, "#endif\n"); } if (eventmap) { eventmapnr = fproc(eventmap); fprintf(th, "#define EVENT_TRACE %d\n", eventmapnr); - fprintf(th, "#define endevent endstate%d\n", eventmapnr); + fprintf(th, "#define endevent _endstate%d\n", eventmapnr); if (eventmap[2] == 'o') /* ":notrace:" */ fprintf(th, "#define NEGATED_TRACE 1\n"); } - fprintf(th, "typedef struct S_F_MAP {\n"); - fprintf(th, " char *fnm; int from; int upto;\n"); + fprintf(th, "\ntypedef struct S_F_MAP {\n"); + fprintf(th, " char *fnm;\n\tint from;\n\tint upto;\n"); fprintf(th, "} S_F_MAP;\n"); - fprintf(tc, "/*** Generated by %s ***/\n", Version); + fprintf(tc, "/*** Generated by %s ***/\n", SpinVersion); fprintf(tc, "/*** From source: %s ***/\n\n", oFname->name); ntimes(tc, 0, 1, Pre0); @@ -304,19 +461,36 @@ doless: case 2: fprintf(tc, "#include \"pan_t.h\"\n"); break; } + if (separate != 2) + { fprintf(tc, "char *TrailFile = PanSource; /* default */\n"); + fprintf(tc, "char *trailfilename;\n"); + } + + fprintf(tc, "#ifdef LOOPSTATE\n"); + fprintf(tc, "double cnt_loops;\n"); + fprintf(tc, "#endif\n"); + fprintf(tc, "State A_Root; /* seed-state for cycles */\n"); fprintf(tc, "State now; /* the full state-vector */\n"); + fprintf(tc, "#if NQS > 0\n"); + fprintf(tc, "short q_flds[NQS+1];\n"); + fprintf(tc, "short q_max[NQS+1];\n"); + fprintf(tc, "#endif\n"); + plunk_c_fcts(tc); /* State can be used in fcts */ if (separate != 2) - ntimes(tc, 0, 1, Preamble); - else - fprintf(tc, "extern int verbose; extern long depth;\n"); + { ntimes(tc, 0, 1, Preamble); + ntimes(tc, 0, 1, Separate); /* things that moved out of pan.h */ + } else + { fprintf(tc, "extern int verbose;\n"); + fprintf(tc, "extern long depth, depthfound;\n"); + } fprintf(tc, "#ifndef NOBOUNDCHECK\n"); - fprintf(tc, "#define Index(x, y)\tBoundcheck(x, y, II, tt, t)\n"); + fprintf(tc, " #define Index(x, y)\tBoundcheck(x, y, II, tt, t)\n"); fprintf(tc, "#else\n"); - fprintf(tc, "#define Index(x, y)\tx\n"); + fprintf(tc, " #define Index(x, y)\tx\n"); fprintf(tc, "#endif\n"); c_preview(); /* sets hastrack */ @@ -335,7 +509,7 @@ doless: fprintf(tt, "}\n\n"); fprintf(tt, "void\nputpeg(int n, int m)\n"); fprintf(tt, "{ printf(\"%%5d\ttrans %%4d \", m, n);\n"); - fprintf(tt, " printf(\"file %%s line %%3d\\n\",\n"); + fprintf(tt, " printf(\"%%s:%%d\\n\",\n"); fprintf(tt, " T_SRC[n].fl, T_SRC[n].ln);\n"); fprintf(tt, "}\n"); if (!merger) @@ -359,13 +533,18 @@ doless: } fprintf(tm, "#define rand pan_rand\n"); + fprintf(tm, "#define pthread_equal(a,b) ((a)==(b))\n"); fprintf(tm, "#if defined(HAS_CODE) && defined(VERBOSE)\n"); - fprintf(tm, " printf(\"Pr: %%d Tr: %%d\\n\", II, t->forw);\n"); + fprintf(tm, " #ifdef BFS_PAR\n"); + fprintf(tm, " bfs_printf(\"Pr: %%d Tr: %%d\\n\", II, t->forw);\n"); + fprintf(tm, " #else\n"); + fprintf(tm, " cpu_printf(\"Pr: %%d Tr: %%d\\n\", II, t->forw);\n"); + fprintf(tm, " #endif\n"); fprintf(tm, "#endif\n"); fprintf(tm, " switch (t->forw) {\n"); } else { fprintf(tt, "#ifndef PEG\n"); - fprintf(tt, "#define tr_2_src(m,f,l)\n"); + fprintf(tt, " #define tr_2_src(m,f,l)\n"); fprintf(tt, "#endif\n"); fprintf(tt, "void\nset_claim(void)\n{\tTrans *T;\n"); fprintf(tt, "\textern Trans ***trans;\n"); @@ -373,8 +552,9 @@ doless: fprintf(tt, " char *, int, int, int);\n\n"); fprintf(tm, "#define rand pan_rand\n"); + fprintf(tm, "#define pthread_equal(a,b) ((a)==(b))\n"); fprintf(tm, "#if defined(HAS_CODE) && defined(VERBOSE)\n"); - fprintf(tm, " printf(\"Pr: %%d Tr: %%d\\n\", II, forw);\n"); + fprintf(tm, " cpu_printf(\"Pr: %%d Tr: %%d\\n\", II, forw);\n"); fprintf(tm, "#endif\n"); fprintf(tm, " switch (forw) {\n"); } @@ -404,24 +584,47 @@ doless: fprintf(tb, " case 0: goto R999; /* nothing to undo */\n"); for (p = rdy; p; p = p->nxt) - 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"); - fprintf(th, "short *frm_st0;\n"); /* records src states for transitions in never claim */ - } else - { fprintf(th, "extern short *frm_st0;\n"); + { putproc(p); } - gencodetable(th); + if (separate != 2) + { fprintf(th, "\n"); + for (p = rdy; p; p = p->nxt) + fprintf(th, "extern short src_ln%d[];\n", p->tn); + for (p = rdy; p; p = p->nxt) + fprintf(th, "extern S_F_MAP src_file%d[];\n", p->tn); + fprintf(th, "\n"); + + fprintf(tc, "uchar reached%d[3]; /* np_ */\n", nrRdy); + fprintf(tc, "uchar *loopstate%d; /* np_ */\n", nrRdy); + + fprintf(tc, "struct {\n"); + fprintf(tc, " int tp; short *src;\n"); + fprintf(tc, "} src_all[] = {\n"); + for (p = rdy; p; p = p->nxt) + fprintf(tc, " { %d, &src_ln%d[0] },\n", + p->tn, p->tn); + fprintf(tc, " { 0, (short *) 0 }\n"); + fprintf(tc, "};\n"); + + fprintf(tc, "S_F_MAP *flref[] = {\n"); /* 5.3.0 */ + for (p = rdy; p; p = p->nxt) + { fprintf(tc, " src_file%d%c\n", p->tn, p->nxt?',':' '); + } + fprintf(tc, "};\n\n"); + } else + { fprintf(tc, "extern uchar reached%d[3]; /* np_ */\n", nrRdy); + } + + gencodetable(tc); /* was th */ + + if (Unique < (1 << (8*sizeof(unsigned char)) )) /* was uniq before */ + { fprintf(th, "#define T_ID unsigned char\n"); + } else if (Unique < (1 << (8*sizeof(unsigned short)) )) + { fprintf(th, "#define T_ID unsigned short\n"); + } else + { fprintf(th, "#define T_ID unsigned int\n"); + } if (separate != 1) { tm_predef_np(); @@ -438,13 +641,13 @@ doless: genheader(); 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 BACKWARD_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 { fprintf(th, "#define FORWARD_MOVES\t\"pan.m\"\n"); - fprintf(th, "#define REVERSE_MOVES\t\"pan.b\"\n"); + fprintf(th, "#define BACKWARD_MOVES\t\"pan.b\"\n"); fprintf(th, "#define TRANSITIONS\t\"pan.t\"\n"); } genaddproc(); @@ -456,33 +659,37 @@ doless: if (!run) fatal("no runable process", (char *)0); fprintf(tc, "void\n"); fprintf(tc, "active_procs(void)\n{\n"); + + fprintf(tc, " if (reversing == 0) {\n"); reverse_procs(run); + fprintf(tc, " } else {\n"); + forward_procs(run); + fprintf(tc, " }\n"); + fprintf(tc, "}\n"); ntimes(tc, 0, 1, Dfa); ntimes(tc, 0, 1, Xpt); fprintf(th, "#define NTRANS %d\n", uniq); - fprintf(th, "#ifdef PEG\n"); - fprintf(th, "long peg[NTRANS];\n"); - fprintf(th, "#endif\n"); - if (u_sync && !u_async) - spit_recvs(th, tc); + { spit_recvs(th, tc); + } } else { genheader(); fprintf(th, "#define FORWARD_MOVES\t\"pan_t.m\"\n"); - fprintf(th, "#define REVERSE_MOVES\t\"pan_t.b\"\n"); + fprintf(th, "#define BACKWARD_MOVES\t\"pan_t.b\"\n"); fprintf(th, "#define TRANSITIONS\t\"pan_t.t\"\n"); fprintf(tc, "extern int Maxbody;\n"); fprintf(tc, "#if VECTORSZ>32000\n"); - fprintf(tc, "extern int proc_offset[];\n"); + fprintf(tc, " extern int *proc_offset;\n"); fprintf(tc, "#else\n"); - fprintf(tc, "extern short proc_offset[];\n"); + fprintf(tc, " extern short *proc_offset;\n"); fprintf(tc, "#endif\n"); - fprintf(tc, "extern uchar proc_skip[];\n"); + fprintf(tc, "extern uchar *proc_skip;\n"); fprintf(tc, "extern uchar *reached[];\n"); fprintf(tc, "extern uchar *accpstate[];\n"); fprintf(tc, "extern uchar *progstate[];\n"); + fprintf(tc, "extern uchar *loopstate[];\n"); fprintf(tc, "extern uchar *stopstate[];\n"); fprintf(tc, "extern uchar *visstate[];\n\n"); fprintf(tc, "extern short *mapstate[];\n"); @@ -491,7 +698,7 @@ doless: fprintf(tc, "\textern State now;\n"); fprintf(tc, "\textern void set_claim(void);\n\n"); fprintf(tc, "#ifdef PROV\n"); - fprintf(tc, "#include PROV\n"); + fprintf(tc, " #include PROV\n"); fprintf(tc, "#endif\n"); fprintf(tc, "\tset_claim();\n"); genother(); @@ -509,13 +716,42 @@ doless: 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); } + + fprintf(th, "#if defined(BFS_PAR) || NCORE>1\n"); + fprintf(th, " void e_critical(int);\n"); + fprintf(th, " void x_critical(int);\n"); + fprintf(th, " #ifdef BFS_PAR\n"); + fprintf(th, " void bfs_main(int, int);\n"); + fprintf(th, " void bfs_report_mem(void);\n"); + fprintf(th, " #endif\n"); + fprintf(th, "#endif\n"); + + fprintf(th, "\n\n/* end of PAN_H */\n#endif\n"); + fclose(th); + fclose(tt); + fclose(tm); + fclose(tb); + + if (!(th = fopen("pan.p", MFLAGS))) + { printf("spin: cannot create pan.p for -DBFS_PAR\n"); + return; /* we're done anyway */ + } + + ntimes(th, 0, 1, pan_par); /* BFS_PAR */ + fclose(th); + + fprintf(tc, "\nTrans *t_id_lkup[%d];\n\n", globmax+1); + + if (separate != 2) + { fprintf(tc, "\n#ifdef BFS_PAR\n\t#include \"pan.p\"\n#endif\n"); + } + fprintf(tc, "\n/* end of pan.c */\n"); + fclose(tc); } static int @@ -537,13 +773,13 @@ dolen(Symbol *s, char *pre, int pid, int ai, int qln) fprintf(tc, "%s(", pre); if (!(s->hidden&1)) { if (s->context) - fprintf(tc, "((P%d *)this)->", pid); + fprintf(tc, "(int) ( ((P%d *)this)->", pid); else - fprintf(tc, "now."); + fprintf(tc, "(int) ( now."); } fprintf(tc, "%s", s->name); - if (qln > 1) fprintf(tc, "[%d]", ai); - fprintf(tc, ")"); + if (qln > 1 || s->isarray) fprintf(tc, "[%d]", ai); + fprintf(tc, ") )"); } struct AA { char TT[9]; char CC[8]; }; @@ -712,47 +948,60 @@ genconditionals(void) fprintf(tc, "}\n"); } +extern int find_min(Sequence *); +extern int find_max(Sequence *); + static void putproc(ProcList *p) { Pid = p->tn; Det = p->det; - if (Pid == claimnr + if (pid_is_claim(Pid) && separate == 1) { fprintf(th, "extern uchar reached%d[];\n", Pid); #if 0 - fprintf(th, "extern short nstates%d;\n", Pid); + fprintf(th, "extern short _nstates%d;\n", Pid); #else - fprintf(th, "\n#define nstates%d %d\t/* %s */\n", + fprintf(th, "\n#define _nstates%d %d\t/* %s */\n", Pid, p->s->maxel, p->n->name); #endif fprintf(th, "extern short src_ln%d[];\n", Pid); + fprintf(th, "extern uchar *loopstate%d;\n", Pid); fprintf(th, "extern S_F_MAP src_file%d[];\n", Pid); - fprintf(th, "#define endstate%d %d\n", + fprintf(th, "#define _endstate%d %d\n", Pid, p->s->last?p->s->last->seqno:0); - fprintf(th, "#define src_claim src_ln%d\n", claimnr); - return; } - if (Pid != claimnr + if (!pid_is_claim(Pid) && separate == 2) { fprintf(th, "extern short src_ln%d[];\n", Pid); + fprintf(th, "extern uchar *loopstate%d;\n", Pid); return; } AllGlobal = (p->prov)?1:0; /* process has provided clause */ - fprintf(th, "\n#define nstates%d %d\t/* %s */\n", + fprintf(th, "\n#define _nstates%d %d\t/* %s */\n", Pid, p->s->maxel, p->n->name); - if (Pid == claimnr) - fprintf(th, "#define nstates_claim nstates%d\n", Pid); - if (Pid == eventmapnr) - fprintf(th, "#define nstates_event nstates%d\n", Pid); +/* new */ + fprintf(th, "#define minseq%d %d\n", Pid, find_min(p->s)); + fprintf(th, "#define maxseq%d %d\n", Pid, find_max(p->s)); - fprintf(th, "#define endstate%d %d\n", - Pid, p->s->last->seqno); - fprintf(tm, "\n /* PROC %s */\n", p->n->name); - fprintf(tb, "\n /* PROC %s */\n", p->n->name); +/* end */ + + if (Pid == eventmapnr) + fprintf(th, "#define nstates_event _nstates%d\n", Pid); + + fprintf(th, "#define _endstate%d %d\n", Pid, p->s->last?p->s->last->seqno:0); + + if (p->b == N_CLAIM || p->b == E_TRACE || p->b == N_TRACE) + { fprintf(tm, "\n /* CLAIM %s */\n", p->n->name); + fprintf(tb, "\n /* CLAIM %s */\n", p->n->name); + } + else + { fprintf(tm, "\n /* PROC %s */\n", p->n->name); + fprintf(tb, "\n /* PROC %s */\n", p->n->name); + } fprintf(tt, "\n /* proctype %d: %s */\n", Pid, p->n->name); fprintf(tt, "\n trans[%d] = (Trans **)", Pid); fprintf(tt, " emalloc(%d*sizeof(Trans *));\n\n", p->s->maxel); @@ -761,7 +1010,6 @@ putproc(ProcList *p) { 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"); @@ -947,10 +1195,10 @@ put_sub(Element *e, int Tt0, int Tt1) if (e->n->ntyp == D_STEP) { int inherit = (e->status&(ATOM|L_ATOM)); fprintf(tm, "\tcase %d: ", uniq++); - fprintf(tm, "/* STATE %d - line %d %s - [", - e->seqno, e->n->ln, e->n->fn->name); + fprintf(tm, "// STATE %d - %s:%d - [", + e->seqno, e->n->fn->name, e->n->ln); comment(tm, e->n, 0); - fprintf(tm, "] */\n\t\t"); + fprintf(tm, "]\n\t\t"); if (s->last->n->ntyp == BREAK) OkBreak = target(huntele(s->last->nxt, @@ -971,7 +1219,7 @@ put_sub(Element *e, int Tt0, int Tt1) } fprintf(tb, "\tcase %d: ", uniq-1); - fprintf(tb, "/* STATE %d */\n", e->seqno); + fprintf(tb, "// STATE %d\n", e->seqno); fprintf(tb, "\t\tsv_restor();\n"); fprintf(tb, "\t\tgoto R999;\n"); if (e->nxt) @@ -1024,7 +1272,7 @@ typedef struct CaseCache { struct CaseCache *nxt; } CaseCache; -CaseCache *casing[6]; +static CaseCache *casing[6]; static int identical(Lextok *p, Lextok *q) @@ -1076,6 +1324,9 @@ advance(Element *e, int stopat) if (stopat) while (f && f->seqno != stopat) { f = findnext(f); + if (!f) + { break; + } switch (f->n->ntyp) { case GOTO: case '.': @@ -1084,8 +1335,7 @@ advance(Element *e, int stopat) break; default: return f; - } - } + } } return (Element *) 0; } @@ -1107,18 +1357,16 @@ equiv_merges(Element *a, Element *b) if (!stopat_a && !stopat_b) return 1; - for (;;) - { - f = advance(a, stopat_a); - g = advance(b, stopat_b); - if (!f && !g) - return 1; - if (f && g) - return identical(f->n, g->n); - else - return 0; - } - return 1; + f = advance(a, stopat_a); + g = advance(b, stopat_b); + + if (!f && !g) + return 1; + + if (f && g) + return identical(f->n, g->n); + + return 0; } static CaseCache * @@ -1174,6 +1422,7 @@ nr_bup(Element *e) switch (e->n->ntyp) { case ASGN: + if (check_track(e->n) == STRUCT) { break; } nr++; break; case 'r': @@ -1234,10 +1483,10 @@ nrhops(Element *e) } if (f && !f->merge && !f->merge_single && f->seqno != stopat) - { fprintf(tm, "\n\t\tbad hop %s:%d -- at %d, <", + { fprintf(tm, "\n\t\t// bad 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", + fprintf(tm, "> looking for %d -- merge %d:%d:%d ", stopat, f->merge, f->merge_start, f->merge_single); break; } @@ -1258,18 +1507,20 @@ check_needed(void) } static void -doforward(FILE *tm, Element *e) +doforward(FILE *tm_fd, Element *e) { FSM_use *u; - putstmnt(tm, e->n, e->seqno); + putstmnt(tm_fd, e->n, e->seqno); if (e->n->ntyp != ELSE && Det) - { fprintf(tm, ";\n\t\tif (trpt->o_pm&1)\n\t\t"); - fprintf(tm, "\tuerror(\"non-determinism in D_proctype\")"); + { fprintf(tm_fd, ";\n\t\tif (trpt->o_pm&1)\n\t\t"); + fprintf(tm_fd, "\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 */ ", + { fprintf(tm_fd, ";\n\t\t"); + fprintf(tm_fd, "if (TstOnly) return 1; /* TT */\n"); + fprintf(tm_fd, "\t\t/* dead %d: %s */ ", u->special, u->var->name); switch (u->special) { @@ -1281,10 +1532,10 @@ doforward(FILE *tm, Element *e) } 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"); + fprintf(tm_fd, "\n#ifdef HAS_CODE\n"); + fprintf(tm_fd, "\t\tif (!readtrail)\n"); + fprintf(tm_fd, "#endif\n\t\t\t"); + putname(tm_fd, "", &XZ, 0, " = 0"); break; } /* else fall through */ case 1: /* dead after read -- add asgn of rval -- needs bup */ @@ -1292,20 +1543,20 @@ doforward(FILE *tm, Element *e) CnT[YZcnt]++; /* this step added bups */ if (multi_oval) { check_needed(); - fprintf(tm, "(trpt+1)->bup.ovals[%d] = ", + fprintf(tm_fd, "(trpt+1)->bup.ovals[%d] = ", multi_oval-1); multi_oval++; } else - fprintf(tm, "(trpt+1)->bup.oval = "); - 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"); + fprintf(tm_fd, "(trpt+1)->bup.oval = "); + putname(tm_fd, "", &YZ[YZmax], 0, ";\n"); + fprintf(tm_fd, "#ifdef HAS_CODE\n"); + fprintf(tm_fd, "\t\tif (!readtrail)\n"); + fprintf(tm_fd, "#endif\n\t\t\t"); + putname(tm_fd, "", &YZ[YZmax], 0, " = 0"); YZmax++; break; } } - fprintf(tm, ";\n\t\t"); + fprintf(tm_fd, ";\n\t\t"); } static int @@ -1318,7 +1569,7 @@ dobackward(Element *e, int casenr) if (!didcase) { fprintf(tb, "\n\tcase %d: ", casenr); - fprintf(tb, "/* STATE %d */\n\t\t", e->seqno); + fprintf(tb, "// STATE %d\n\t\t", e->seqno); didcase++; } @@ -1412,7 +1663,7 @@ case_cache(Element *e, int a) { int bupcase = 0, casenr = uniq, fromcache = 0; CaseCache *Cached = (CaseCache *) 0; Element *f, *g; - int j, nrbups, mark, target; + int j, nrbups, mark, ntarget; extern int ccache; mark = (e->status&ATOM); /* could lose atomicity in a merge chain */ @@ -1439,17 +1690,17 @@ case_cache(Element *e, int a) fprintf(tt, "\ttrans[%d][%d]\t= ", Pid, e->seqno); if (ccache - && Pid != claimnr + && !pid_is_claim(Pid) && Pid != eventmapnr && (Cached = prev_case(e, Pid))) { bupcase = Cached->b; casenr = Cached->m; fromcache = 1; - fprintf(tm, "/* STATE %d - line %d %s - [", - e->seqno, e->n->ln, e->n->fn->name); + fprintf(tm, "// STATE %d - %s:%d - [", + e->seqno, e->n->fn->name, e->n->ln); comment(tm, e->n, 0); - fprintf(tm, "] (%d:%d - %d) same as %d (%d:%d - %d) */\n", + fprintf(tm, "] (%d:%d - %d) same as %d (%d:%d - %d)\n", e->merge_start, e->merge, e->merge_in, casenr, Cached->e->merge_start, Cached->e->merge, Cached->e->merge_in); @@ -1457,17 +1708,17 @@ case_cache(Element *e, int a) goto gotit; } - fprintf(tm, "\tcase %d: /* STATE %d - line %d %s - [", - uniq++, e->seqno, e->n->ln, e->n->fn->name); + fprintf(tm, "\tcase %d: // STATE %d - %s:%d - [", + uniq++, e->seqno, e->n->fn->name, e->n->ln); comment(tm, e->n, 0); nrbups = (e->merge || e->merge_start) ? nrhops(e) : nr_bup(e); - fprintf(tm, "] (%d:%d:%d - %d) */\n\t\t", + fprintf(tm, "] (%d:%d:%d - %d)\n\t\t", e->merge_start, e->merge, nrbups, e->merge_in); if (nrbups > MAXMERGE-1) fatal("merge requires more than 256 bups", (char *)0); - if (e->n->ntyp != 'r' && Pid != claimnr && Pid != eventmapnr) + if (e->n->ntyp != 'r' && !pid_is_claim(Pid) && Pid != eventmapnr) fprintf(tm, "IfNotBlocked\n\t\t"); if (multi_needed != 0 || multi_undo != 0) @@ -1482,18 +1733,29 @@ case_cache(Element *e, int a) memset(CnT, 0, sizeof(CnT)); YZmax = YZcnt = 0; -/* NEW 4.2.6 */ - if (Pid == claimnr) - { - fprintf(tm, "\n#if defined(VERI) && !defined(NP)\n\t\t"); - fprintf(tm, "{ static int reported%d = 0;\n\t\t", e->seqno); - /* source state changes in retrans and must be looked up in frm_st0[t->forw] */ - fprintf(tm, " if (verbose && !reported%d)\n\t\t", e->seqno); - fprintf(tm, " { printf(\"depth %%d: Claim reached state %%d (line %%d)\\n\",\n\t\t"); - fprintf(tm, " depth, frm_st0[t->forw], src_claim[%d]);\n\t\t", e->seqno); - fprintf(tm, " reported%d = 1;\n\t\t", e->seqno); - fprintf(tm, " fflush(stdout);\n\t\t"); - fprintf(tm, "} }\n"); +/* new 4.2.6, revised 6.0.0 */ + if (pid_is_claim(Pid)) + { fprintf(tm, "\n#if defined(VERI) && !defined(NP)\n"); + fprintf(tm, "#if NCLAIMS>1\n\t\t"); + fprintf(tm, "{ static int reported%d = 0;\n\t\t", e->seqno); + fprintf(tm, " if (verbose && !reported%d)\n\t\t", e->seqno); + fprintf(tm, " { int nn = (int) ((Pclaim *)pptr(0))->_n;\n\t\t"); + fprintf(tm, " printf(\"depth %%ld: Claim %%s (%%d), state %%d (line %%d)\\n\",\n\t\t"); + fprintf(tm, " depth, procname[spin_c_typ[nn]], nn, "); + fprintf(tm, "(int) ((Pclaim *)pptr(0))->_p, src_claim[ (int) ((Pclaim *)pptr(0))->_p ]);\n\t\t"); + fprintf(tm, " reported%d = 1;\n\t\t", e->seqno); + fprintf(tm, " fflush(stdout);\n\t\t"); + fprintf(tm, "} }\n"); + fprintf(tm, "#else\n\t\t"); + fprintf(tm, "{ static int reported%d = 0;\n\t\t", e->seqno); + fprintf(tm, " if (verbose && !reported%d)\n\t\t", e->seqno); + fprintf(tm, " { printf(\"depth %%d: Claim, state %%d (line %%d)\\n\",\n\t\t"); + fprintf(tm, " (int) depth, (int) ((Pclaim *)pptr(0))->_p, "); + fprintf(tm, "src_claim[ (int) ((Pclaim *)pptr(0))->_p ]);\n\t\t"); + fprintf(tm, " reported%d = 1;\n\t\t", e->seqno); + fprintf(tm, " fflush(stdout);\n\t\t"); + fprintf(tm, "} }\n"); + fprintf(tm, "#endif\n"); fprintf(tm, "#endif\n\t\t"); } /* end */ @@ -1504,32 +1766,32 @@ case_cache(Element *e, int a) doforward(tm, e); if (e->merge_start) - target = e->merge_start; + ntarget = e->merge_start; else - target = e->merge; + ntarget = e->merge; - if (target) + if (ntarget) { f = e; more: if (f->n->ntyp == GOTO) { g = get_lab(f->n, 1); - if (g->seqno == target) + if (g->seqno == ntarget) f = g; else - f = huntele(g, f->status, target); + f = huntele(g, f->status, ntarget); } else f = f->nxt; - if (f && f->seqno != target) + if (f && f->seqno != ntarget) { if (!f->merge && !f->merge_single) { fprintf(tm, "/* stop at bad hop %d, %d */\n\t\t", - f->seqno, target); + f->seqno, ntarget); 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, "(%d, %d, %d) */\n\t\t", f->merge, f->seqno, ntarget); fprintf(tm, "reached[%d][%d] = 1;\n\t\t", Pid, f->seqno); YZcnt++; lab_transfer(e, f); @@ -1547,8 +1809,8 @@ out: multi_needed = 0; didcase = 0; - if (target) - lastfirst(target, e, casenr); /* mergesteps only */ + if (ntarget) + lastfirst(ntarget, e, casenr); /* mergesteps only */ dobackward(e, casenr); /* the original step */ @@ -1557,7 +1819,7 @@ out: if (e->merge || e->merge_start) { if (!didcase) { fprintf(tb, "\n\tcase %d: ", casenr); - fprintf(tb, "/* STATE %d */", e->seqno); + fprintf(tb, "// STATE %d", e->seqno); didcase++; } else fprintf(tb, ";"); @@ -1607,8 +1869,8 @@ put_el(Element *e, int Tt0, int Tt1) } else a = 0; if (g - && (g->status&CHECK2 /* entering remotely ref'd state */ - || e->status&CHECK2)) /* leaving remotely ref'd state */ + && ((g->status&CHECK2) /* entering remotely ref'd state */ + || (e->status&CHECK2))) /* leaving remotely ref'd state */ e->status |= I_GLOB; /* don't remove dead edges in here, to preserve structure of fsm */ @@ -1758,8 +2020,8 @@ put_seq(Sequence *s, int Tt0, int Tt1) { fprintf(tt, "#if 0\n\t/* dead link: */\n"); deadlink = 1; if (verbose&32) - printf("spin: line %3d %s, Warning: condition is always false\n", - g->n->ln, g->n->fn?g->n->fn->name:""); + printf("spin: %s:%d, warning, condition is always false\n", + g->n->fn?g->n->fn->name:"", g->n->ln); } else deadlink = 0; if (0) printf(" settr %d %d\n", a, 0); @@ -1867,7 +2129,7 @@ find_target(Element *e) case BREAK: if (e->nxt) { f = find_target(huntele(e->nxt, e->status, -1)); - break; /* 4.3.0 -- was missing */ + break; /* new 5.0 -- was missing */ } /* else fall through */ default: @@ -1887,6 +2149,26 @@ target(Element *e) return find_target(e); } +static int +seq_has_el(Sequence *s, Element *g) /* new to version 5.0 */ +{ Element *f; + SeqList *h; + + for (f = s->frst; f; f = f->nxt) /* g in same atomic? */ + { if (f == g) + { return 1; + } + if (f->status & CHECK3) + { continue; + } + f->status |= CHECK3; /* protect against cycles */ + for (h = f->sub; h; h = h->nxt) + { if (h->this && seq_has_el(h->this, g)) + { return 1; + } } } + return 0; +} + static int scan_seq(Sequence *s) { Element *f, *g; @@ -1896,20 +2178,22 @@ scan_seq(Sequence *s) { if ((f->status&CHECK2) || has_global(f->n)) return 1; - if (f->n->ntyp == GOTO) /* may reach other atomic */ - { -#if 0 - /* if jumping from an atomic without globals into - * one with globals, this does the wrong thing + if (f->n->ntyp == GOTO /* may exit or reach other atomic */ + && !(f->status & D_ATOM)) /* cannot jump from d_step */ + { /* consider jump from an atomic without globals into + * an atomic with globals * example by Claus Traulsen, 22 June 2007 */ g = target(f); +#if 1 + if (g && !seq_has_el(s, g)) /* not internal to this atomic/dstep */ + +#else if (g && !(f->status & L_ATOM) && !(g->status & (ATOM|L_ATOM))) #endif - { fprintf(tt, " /* mark-down line %d */\n", - f->n->ln); + { fprintf(tt, "\t/* mark-down line %d status %d = %d */\n", f->n->ln, f->status, (f->status & D_ATOM)); return 1; /* assume worst case */ } } for (h = f->sub; h; h = h->nxt) @@ -1937,9 +2221,26 @@ glob_args(Lextok *n) return result; } +static int +proc_is_safe(const Lextok *n) +{ ProcList *p; + /* not safe unless no local var inits are used */ + /* note that a local variable init could refer to a global */ + + for (p = rdy; p; p = p->nxt) + { if (strcmp(n->sym->name, p->n->name) == 0) + { /* printf("proc %s safety: %d\n", p->n->name, p->unsafe); */ + return (p->unsafe != 0); + } } +/* non_fatal("bad call to proc_is_safe", (char *) 0); */ + /* cannot happen */ + return 0; +} + int has_global(Lextok *n) -{ Lextok *v; extern int runsafe; +{ Lextok *v; + static Symbol *n_seen = (Symbol *) 0; if (!n) return 0; if (AllGlobal) return 1; /* global provided clause */ @@ -1968,6 +2269,14 @@ has_global(Lextok *n) case LEN: return (((n->sym->xu)&(XR|XS|XX)) != (XR|XS)); case NAME: + if (strcmp(n->sym->name, "_priority") == 0) + { if (old_priority_rules) + { if (n_seen != n->sym) + fatal("cannot refer to _priority with -o6", (char *) 0); + n_seen = n->sym; + } + return 0; + } if (n->sym->context || (n->sym->hidden&64) || strcmp(n->sym->name, "_pid") == 0 @@ -1975,14 +2284,15 @@ has_global(Lextok *n) return 0; return 1; - case RUN: return 1-runsafe; + case RUN: + return proc_is_safe(n); 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: + case 'p': case 'q': + case TIMEOUT: case SET_P: case GET_P: return 1; /* @ was 1 (global) since 2.8.5 @@ -2017,11 +2327,12 @@ static void Bailout(FILE *fd, char *str) { if (!GenCode) - fprintf(fd, "continue%s", str); - else if (IsGuard) - fprintf(fd, "%s%s", NextLab[Level], str); - else - fprintf(fd, "Uerror(\"block in step seq\")%s", str); + { fprintf(fd, "continue%s", str); + } else if (IsGuard) + { fprintf(fd, "%s%s", NextLab[Level], str); + } else + { fprintf(fd, "Uerror(\"block in d_step seq\")%s", str); + } } #define cat0(x) putstmnt(fd,now->lft,m); fprintf(fd, x); \ @@ -2029,6 +2340,7 @@ Bailout(FILE *fd, char *str) #define cat1(x) fprintf(fd,"("); cat0(x); fprintf(fd,")") #define cat2(x,y) fprintf(fd,x); putstmnt(fd,y,m) #define cat3(x,y,z) fprintf(fd,x); putstmnt(fd,y,m); fprintf(fd,z) +#define cat30(x,y,z) fprintf(fd,x,0); putstmnt(fd,y,m); fprintf(fd,z) void putstmnt(FILE *fd, Lextok *now, int m) @@ -2070,12 +2382,14 @@ putstmnt(FILE *fd, Lextok *now, int m) else fprintf(fd, "((trpt->tau)&1)"); if (GenCode) - printf("spin: line %3d, warning: 'timeout' in d_step sequence\n", - lineno); + printf("spin: %s:%d, warning, 'timeout' in d_step sequence\n", + Fname->name, lineno); /* is okay as a guard */ break; case RUN: + if (now->sym == NULL) + fatal("internal error pangen2.c", (char *) 0); if (claimproc && strcmp(now->sym->name, claimproc) == 0) fatal("claim %s, (not runnable)", claimproc); @@ -2084,29 +2398,57 @@ putstmnt(FILE *fd, Lextok *now, int m) fatal("eventmap %s, (not runnable)", eventmap); if (GenCode) - fatal("'run' in d_step sequence (use atomic)", - (char *)0); + fatal("'run' in d_step sequence (use atomic)", (char *)0); - fprintf(fd,"addproc(%d", fproc(now->sym->name)); + fprintf(fd,"addproc(II, %d, %d", + (now->val > 0 && !old_priority_rules) ? now->val : 1, + fproc(now->sym->name)); for (v = now->lft, i = 0; v; v = v->rgt, i++) { cat2(", ", v->lft); } check_param_count(i, now); if (i > Npars) - { printf("\t%d parameters used, max %d expected\n", i, Npars); - fatal("too many parameters in run %s(...)", - now->sym->name); + { /* printf("\t%d parameters used, max %d expected\n", i, Npars); */ + fatal("too many parameters in run %s(...)", now->sym->name); } for ( ; i < Npars; i++) fprintf(fd, ", 0"); fprintf(fd, ")"); +#if 0 + /* process now->sym->name has run priority now->val */ + if (now->val > 0 && now->val < 256 && !old_priority_rules) + { fprintf(fd, " && (((P0 *)pptr(now._nr_pr - 1))->_priority = %d)", now->val); + } +#endif + if (now->val < 0 || now->val > 255) /* 0 itself is allowed */ + { fatal("bad process in run %s, valid range: 1..255", now->sym->name); + } break; case ENABLED: cat3("enabled(II, ", now->lft, ")"); break; + case GET_P: + if (old_priority_rules) + { fprintf(fd, "1"); + } else + { cat3("get_priority(", now->lft, ")"); + } + break; + + case SET_P: + if (!old_priority_rules) + { fprintf(fd, "if (TstOnly) return 1; /* T30 */\n\t\t"); + fprintf(fd, "set_priority("); + putstmnt(fd, now->lft->lft, m); + fprintf(fd, ", "); + putstmnt(fd, now->lft->rgt, m); + fprintf(fd, ")"); + } + break; + case NONPROGRESS: /* o_pm&4=progress, tau&128=claim stutter */ if (separate == 2) @@ -2180,7 +2522,7 @@ putstmnt(FILE *fd, Lextok *now, int m) case 's': if (Pid == eventmapnr) - { fprintf(fd, "if ((ot == EVENT_TRACE && _tp != 's') "); + { fprintf(fd, "if ((II == -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 @@ -2208,31 +2550,37 @@ putstmnt(FILE *fd, Lextok *now, int m) break; } if (has_xu) - { fprintf(fd, "\n#ifndef XUSAFE\n\t\t"); - putname(fd, "if (q_claim[", now->lft, m, "]&2) "); - putname(fd, "q_S_check(", now->lft, m, ", II);"); - fprintf(fd, "\n#endif\n\t\t"); + { fprintf(fd, "\n#if !defined(XUSAFE) && !defined(NOREDUCE)\n\t\t"); + putname(fd, "if (q_claim[", now->lft, m, "]&2)\n\t\t"); + putname(fd, "{ q_S_check(", now->lft, m, ", II);\n\t\t"); + fprintf(fd, "}\n"); + if (has_sorted && now->val == 1) + { putname(fd, "\t\tif (q_claim[", now->lft, m, "]&1)\n\t\t"); /* &1 iso &2 */ + fprintf(fd, "{ uerror(\"sorted send on xr channel violates po reduction\");\n\t\t"); + fprintf(fd, "}\n"); + } + fprintf(fd, "#endif\n\t\t"); } fprintf(fd, "if (q_%s", (u_sync > 0 && u_async == 0)?"len":"full"); putname(fd, "(", now->lft, m, "))\n"); if (m_loss) - fprintf(fd, "\t\t{ nlost++; delta_m = 1; } else {"); - 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 (has_enabled || has_priority) + fprintf(fd, "\n\t\tif (TstOnly) return 1; /* T1 */"); if (u_sync && !u_async && rvopt) fprintf(fd, "\n\n\t\tif (no_recvs(II)) continue;\n"); fprintf(fd, "\n#ifdef HAS_CODE\n"); fprintf(fd, "\t\tif (readtrail && gui) {\n"); - fprintf(fd, "\t\t\tchar simtmp[32];\n"); + fprintf(fd, "\t\t\tchar simtmp[64];\n"); putname(fd, "\t\t\tsprintf(simvals, \"%%d!\", ", now->lft, m, ");\n"); _isok++; for (v = now->rgt, i = 0; v; v = v->rgt, i++) @@ -2256,9 +2604,9 @@ putstmnt(FILE *fd, Lextok *now, int m) printf(" %d msg parameters sent, %d expected\n", i, Mpars); fatal("too many pars in send", ""); } - for ( ; i < Mpars; i++) + for (j = i; i < Mpars; i++) fprintf(fd, ", 0"); - fprintf(fd, ")"); + fprintf(fd, ", %d)", j); if (u_sync) { fprintf(fd, ";\n\t\t"); if (u_async) @@ -2274,7 +2622,7 @@ putstmnt(FILE *fd, Lextok *now, int m) case 'r': if (Pid == eventmapnr) - { fprintf(fd, "if ((ot == EVENT_TRACE && _tp != 'r') "); + { fprintf(fd, "if ((II == -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 @@ -2342,10 +2690,13 @@ putstmnt(FILE *fd, Lextok *now, int m) break; } if (has_xu) - { fprintf(fd, "\n#ifndef XUSAFE\n\t\t"); - putname(fd, "if (q_claim[", now->lft, m, "]&1) "); - putname(fd, "q_R_check(", now->lft, m, ", II);"); - fprintf(fd, "\n#endif\n\t\t"); + { fprintf(fd, "\n#if !defined(XUSAFE) && !defined(NOREDUCE)\n\t\t"); + putname(fd, "if (q_claim[", now->lft, m, "]&1)\n\t\t"); + putname(fd, "{ q_R_check(", now->lft, m, ", II);\n\t\t"); + if (has_random && now->val != 0) + fprintf(fd, " uerror(\"rand receive on xr channel violates po reduction\");\n\t\t"); + fprintf(fd, "}\n"); + fprintf(fd, "#endif\n\t\t"); } if (u_sync) { if (now->val >= 2) @@ -2398,6 +2749,8 @@ putstmnt(FILE *fd, Lextok *now, int m) fprintf(fd, "0, %d, 0)) ", i); Bailout(fd, ""); } } + if (has_enabled || has_priority) + fprintf(fd, ";\n\t\tif (TstOnly) return 1 /* T2 */"); } else /* random receive: val 1 or 3 */ { fprintf(fd, ";\n\t\tif (!(XX = Q_has("); putname(fd, "", now->lft, m, ""); @@ -2415,19 +2768,21 @@ putstmnt(FILE *fd, Lextok *now, int m) fprintf(fd, ", 0, 0"); fprintf(fd, "))) "); Bailout(fd, ""); - fprintf(fd, ";\n\t\t"); - if (multi_oval) - { check_needed(); - fprintf(fd, "(trpt+1)->bup.ovals[%d] = ", - multi_oval-1); - multi_oval++; - } else - fprintf(fd, "(trpt+1)->bup.oval = "); - fprintf(fd, "XX"); - } - if (has_enabled) - fprintf(fd, ";\n\t\tif (TstOnly) return 1"); + if (has_enabled || has_priority) + fprintf(fd, ";\n\t\tif (TstOnly) return 1 /* T2 */"); + if (!GenCode) { + fprintf(fd, ";\n\t\t"); + if (multi_oval) + { check_needed(); + fprintf(fd, "(trpt+1)->bup.ovals[%d] = ", + multi_oval-1); + multi_oval++; + } else + { fprintf(fd, "(trpt+1)->bup.oval = "); + } + fprintf(fd, "XX"); + } } if (j == 0 && now->val >= 2) { fprintf(fd, ";\n\t\t"); @@ -2439,16 +2794,20 @@ putstmnt(FILE *fd, Lextok *now, int m) fprintf(fd, ";\n\t\t"); /* no variables modified */ if (j == 0 && now->val == 0) - { fprintf(fd, "if (q_flds[((Q0 *)qptr("); + { fprintf(fd, "\n#ifndef BFS_PAR\n\t\t"); + /* q_flds values are not shared among cores */ + fprintf(fd, "if (q_flds[((Q0 *)qptr("); putname(fd, "", now->lft, m, "-1))->_t]"); - fprintf(fd, " != %d)\n\t", i); - fprintf(fd, "\t\tUerror(\"wrong nr of msg fields in rcv\");\n\t\t"); + fprintf(fd, " != %d)\n\t\t\t", i); + fprintf(fd, "Uerror(\"wrong nr of msg fields in rcv\");\n"); + fprintf(fd, "#endif\n\t\t"); } for (v = now->rgt; v; v = v->rgt) - if ((v->lft->ntyp != CONST + { if ((v->lft->ntyp != CONST && v->lft->ntyp != EVAL)) - jj++; /* nr of vars needing bup */ + { jj++; /* nr of vars needing bup */ + } } if (jj) for (v = now->rgt, i = 0; v; v = v->rgt, i++) @@ -2467,12 +2826,12 @@ putstmnt(FILE *fd, Lextok *now, int m) sprintf(tempbuf, "(trpt+1)->bup.oval = "); if (v->lft->sym && !strcmp(v->lft->sym->name, "_")) - { fprintf(fd, tempbuf); + { fprintf(fd, tempbuf, (char *) 0); putname(fd, "qrecv(", now->lft, m, ""); fprintf(fd, ", XX-1, %d, 0);\n\t\t", i); } else { _isok++; - cat3(tempbuf, v->lft, ";\n\t\t"); + cat30(tempbuf, v->lft, ";\n\t\t"); _isok--; } } @@ -2485,7 +2844,7 @@ putstmnt(FILE *fd, Lextok *now, int m) && v->lft->ntyp != EVAL && v->lft->sym && v->lft->sym->type != STRUCT /* not a struct */ - && v->lft->sym->nel == 1 /* not an array */ + && (v->lft->sym->nel == 1 && v->lft->sym->isarray == 0) /* not array */ && strcmp(v->lft->sym->name, "_") != 0) for (w = v->rgt; w; w = w->rgt) if (v->lft->sym == w->lft->sym) @@ -2501,6 +2860,7 @@ putstmnt(FILE *fd, Lextok *now, int m) if (v->lft->ntyp != CONST && v->lft->ntyp != EVAL + && v->lft->sym != NULL && strcmp(v->lft->sym->name, "_") != 0) { nocast=1; _isok++; @@ -2515,6 +2875,7 @@ putstmnt(FILE *fd, Lextok *now, int m) if (v->lft->ntyp != CONST && v->lft->ntyp != EVAL + && v->lft->sym != NULL && strcmp(v->lft->sym->name, "_") != 0 && (v->lft->ntyp != NAME || v->lft->sym->type != CHAN)) @@ -2658,8 +3019,10 @@ putstmnt(FILE *fd, Lextok *now, int m) break; case ASGN: - if (has_enabled) - fprintf(fd, "if (TstOnly) return 1;\n\t\t"); + if (check_track(now) == STRUCT) { break; } + + if (has_enabled || has_priority) + fprintf(fd, "if (TstOnly) return 1; /* T3 */\n\t\t"); _isok++; if (!GenCode) @@ -2669,14 +3032,27 @@ putstmnt(FILE *fd, Lextok *now, int m) sprintf(tempbuf, "(trpt+1)->bup.ovals[%d] = ", multi_oval-1); multi_oval++; - cat3(tempbuf, now->lft, ";\n\t\t"); + cat30(tempbuf, now->lft, ";\n\t\t"); } else { cat3("(trpt+1)->bup.oval = ", now->lft, ";\n\t\t"); } } + if (now->lft->sym + && now->lft->sym->type == PREDEF + && strcmp(now->lft->sym->name, "_") != 0 + && strcmp(now->lft->sym->name, "_priority") != 0) + { fatal("invalid assignment to %s", now->lft->sym->name); + } + nocast = 1; putstmnt(fd,now->lft,m); nocast = 0; fprintf(fd," = "); _isok--; - putstmnt(fd,now->rgt,m); + if (now->lft->sym->isarray + && now->rgt->ntyp == ',') /* array initializer */ + { putstmnt(fd, now->rgt->lft, m); + non_fatal("cannot use an array list initializer here", (char *) 0); + } else + { putstmnt(fd, now->rgt, m); + } if (now->sym->type != CHAN || verbose > 0) @@ -2695,8 +3071,8 @@ putstmnt(FILE *fd, Lextok *now, int m) break; case PRINT: - if (has_enabled) - fprintf(fd, "if (TstOnly) return 1;\n\t\t"); + if (has_enabled || has_priority) + fprintf(fd, "if (TstOnly) return 1; /* T4 */\n\t\t"); #ifdef PRINTF fprintf(fd, "printf(%s", now->sym->name); #else @@ -2709,8 +3085,8 @@ putstmnt(FILE *fd, Lextok *now, int m) break; case PRINTM: - if (has_enabled) - fprintf(fd, "if (TstOnly) return 1;\n\t\t"); + if (has_enabled || has_priority) + fprintf(fd, "if (TstOnly) return 1; /* T5 */\n\t\t"); fprintf(fd, "printm("); if (now->lft && now->lft->ismtyp) fprintf(fd, "%d", now->lft->val); @@ -2732,7 +3108,7 @@ putstmnt(FILE *fd, Lextok *now, int m) case 'q': if (terse) - fprintf(fd, "%s", now->sym->name); + fprintf(fd, "%s", now->sym?now->sym->name:"?"); else fprintf(fd, "%d", remotelab(now)); break; @@ -2748,14 +3124,16 @@ putstmnt(FILE *fd, Lextok *now, int m) 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 (now->sym) + fprintf(fd, "/* %s */\n\t\t", now->sym->name); + if (has_enabled || has_priority) + fprintf(fd, "if (TstOnly) return 1; /* T6 */\n\t\t"); + + if (now->sym) + plunk_inline(fd, now->sym->name, 1, GenCode); + else + fatal("internal error pangen2.c", (char *) 0); + if (!GenCode) { fprintf(fd, "\n"); /* state changed, capture it */ fprintf(fd, "#if defined(C_States) && (HAS_TRACK==1)\n"); @@ -2765,10 +3143,10 @@ putstmnt(FILE *fd, Lextok *now, int m) break; case ASSERT: - if (has_enabled) - fprintf(fd, "if (TstOnly) return 1;\n\t\t"); + if (has_enabled || has_priority) + fprintf(fd, "if (TstOnly) return 1; /* T7 */\n\t\t"); - cat3("assert(", now->lft, ", "); + cat3("spin_assert(", now->lft, ", "); terse = nocast = 1; cat3("\"", now->lft, "\", II, tt, t)"); terse = nocast = 0; @@ -2788,7 +3166,7 @@ putstmnt(FILE *fd, Lextok *now, int m) break; } - if (has_enabled) + if (has_enabled || has_priority) { fprintf(fd, "if (TstOnly)\n\t\t\t"); fprintf(fd, "return (II+1 == now._nr_pr);\n\t\t"); } @@ -2797,16 +3175,30 @@ putstmnt(FILE *fd, Lextok *now, int m) break; default: - printf("spin: bad node type %d (.m) - line %d\n", - now->ntyp, now->ln); - fflush(tm); + printf("spin: error, %s:%d, bad node type %d (.m)\n", + now->fn->name, now->ln, now->ntyp); + fflush(fd); alldone(1); } } +char * +simplify_name(char *s) +{ char *t = s; + + if (!old_scope_rules) + { while (*t == '_' || isdigit((int)*t)) + { t++; + } } + + return t; +} + void putname(FILE *fd, char *pre, Lextok *n, int m, char *suff) /* varref */ { Symbol *s = n->sym; + char *ptr; + lineno = n->ln; Fname = n->fn; if (!s) @@ -2819,48 +3211,67 @@ putname(FILE *fd, char *pre, Lextok *n, int m, char *suff) /* varref */ { fprintf(fd, "%s%s%s", pre, n->sym->name, suff); return; } + if (!s->type) /* not a local name */ s = lookup(s->name); /* must be a global */ if (!s->type) { if (strcmp(pre, ".") != 0) - non_fatal("undeclared variable '%s'", s->name); + fatal("undeclared variable '%s'", s->name); s->type = INT; } if (s->type == PROCTYPE) fatal("proctype-name '%s' used as array-name", s->name); - fprintf(fd, pre); + fprintf(fd, pre, 0); if (!terse && !s->owner && evalindex != 1) - { if (s->context - || strcmp(s->name, "_p") == 0 - || strcmp(s->name, "_pid") == 0) - { fprintf(fd, "((P%d *)this)->", Pid); + { if (old_priority_rules + && strcmp(s->name, "_priority") == 0) + { fprintf(fd, "1"); + goto shortcut; } else - { int x = strcmp(s->name, "_"); - if (!(s->hidden&1) && x != 0) - fprintf(fd, "now."); - if (x == 0 && _isok == 0) - fatal("attempt to read value of '_'", 0); - } } + { if (s->context + || strcmp(s->name, "_p") == 0 + || strcmp(s->name, "_pid") == 0 + || strcmp(s->name, "_priority") == 0) + { fprintf(fd, "((P%d *)this)->", Pid); + } else + { int x = strcmp(s->name, "_"); + if (!(s->hidden&1) && x != 0) + fprintf(fd, "now."); + if (x == 0 && _isok == 0) + fatal("attempt to read value of '_'", 0); + } } } - if (withprocname - && s->context - && strcmp(pre, ".")) - fprintf(fd, "%s:", s->context->name); + if (terse && buzzed == 1) + { fprintf(fd, "B_state.%s", (s->context)?"local[B_pid].":""); + } + + ptr = s->name; + + if (!dont_simplify /* new 6.4.3 */ + && s->type != PREDEF) /* new 6.0.2 */ + { if (withprocname + && s->context + && strcmp(pre, ".")) + { fprintf(fd, "%s:", s->context->name); + ptr = simplify_name(ptr); + } else + { if (terse) + { ptr = simplify_name(ptr); + } } } if (evalindex != 1) - fprintf(fd, "%s", s->name); + fprintf(fd, "%s", ptr); - if (s->nel != 1) + if (s->nel > 1 || s->isarray == 1) { if (no_arrays) - { - non_fatal("ref to array element invalid in this context", - (char *)0); - printf("\thint: instead of, e.g., x[rs] qu[3], use\n"); - printf("\tchan nm_3 = qu[3]; x[rs] nm_3;\n"); - printf("\tand use nm_3 in sends/recvs instead of qu[3]\n"); + { non_fatal("ref to array element invalid in this context", + (char *)0); + printf("\thint: instead of, e.g., x[rs] qu[3], use\n"); + printf("\tchan nm_3 = qu[3]; x[rs] nm_3;\n"); + printf("\tand use nm_3 in sends/recvs instead of qu[3]\n"); } /* an xr or xs reference to an array element * becomes an exclusion tag on the array itself - @@ -2885,15 +3296,32 @@ putname(FILE *fd, char *pre, Lextok *n, int m, char *suff) /* varref */ || (!n->lft && s->nel > 0)) { cat3("[", n->lft, "]"); } else - { cat3("[ Index(", n->lft, ", "); + { /* attempt to catch arrays that are indexed with an array element in the same array + * this causes trouble in the verifier in the backtracking + * e.g., restoring a[?] in the assignment: a [a[1]] = x where a[1] == 1 + * but it is hard when the array is inside a structure, so the names dont match + */ +#if 0 + if (n->lft->ntyp == NAME) + { printf("%4d: Basename %s index %s\n", + n->lft->ln, s->name, n->lft->sym->name); + } +#endif + cat3("[ Index(", n->lft, ", "); fprintf(fd, "%d) ]", s->nel); - } - } - } + } } + } else + { if (n->lft /* effectively a scalar, but with an index */ + && (n->lft->ntyp != CONST + || n->lft->val != 0)) + { fatal("ref to scalar '%s' using array index", (char *) ptr); + } } + if (s->type == STRUCT && n->rgt && n->rgt->lft) { putname(fd, ".", n->rgt->lft, m, ""); } - fprintf(fd, suff); +shortcut: + fprintf(fd, suff, 0); } void @@ -2908,7 +3336,11 @@ putremote(FILE *fd, Lextok *n, int m) /* remote reference */ putstmnt(fd, n->lft->lft, m); /* pid */ fprintf(fd, "]"); } - fprintf(fd, ".%s", n->sym->name); + if (ltl_mode) + { fprintf(fd, ":%s", n->sym->name); + } else + { fprintf(fd, ".%s", n->sym->name); + } } else { if (Sym_typ(n) < SHORT) { promoted = 1; diff --git a/sys/src/cmd/spin/pangen2.h b/sys/src/cmd/spin/pangen2.h index 2df6a0b42..4925053a7 100644 --- a/sys/src/cmd/spin/pangen2.h +++ b/sys/src/cmd/spin/pangen2.h @@ -1,32 +1,15 @@ /***** spin: pangen2.h *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ -static char *Nvr1[] = { /* allow separate compilation */ - "#ifdef VERI", - "void", - "check_claim(int st)", - "{", - " if (st == endclaim)", - " uerror(\"claim violated!\");", - " if (stopstate[VERI][st])", - " uerror(\"end state in claim reached\");", - "}", +static const char *Pre0[] = { + "#ifdef SC", + " #define _FILE_OFFSET_BITS 64", /* allows file sizes greater than 2Gb */ "#endif", - 0, -}; - -static char *Pre0[] = { -"#ifdef SC", - "#define _FILE_OFFSET_BITS 64", /* to allow file sizes greater than 2Gb */ -"#endif", "#include ", "#include ", "#include ", @@ -38,12 +21,14 @@ static char *Pre0[] = { "#include ", "#else", "#include ", - "#include ", /* new 4.3.0 */ + "#include ", "#endif", "#include ", /* defines off_t */ "#include ", + "#include ", "#include ", - "#define Offsetof(X, Y) ((unsigned long)(&(((X *)0)->Y)))", + + "#define Offsetof(X, Y) ((ulong)(&(((X *)0)->Y)))", "#ifndef max", "#define max(a,b) (((a)<(b)) ? (b) : (a))", "#endif", @@ -53,12 +38,62 @@ static char *Pre0[] = { 0, }; -static char *Preamble[] = { +static const char *Separate[] = { + "#ifdef COLLAPSE", + " #if (NCORE>1 && !defined(SEP_STATE)) || defined(BFS_PAR)", + " volatile ulong *ncomps; /* in shared memory */", + " #else", + " ulong ncomps[256+2];", + " #endif", + "#endif", + "Trans ***trans; /* 1 ptr per state per proctype */\n", + "", + "#if VECTORSZ>32000", + " int P_o[MAXPROC], P_o_tmp[MAXPROC+1];", + " int Q_o[MAXQ], Q_o_tmp[MAXPROC+1];", + "", + " int *proc_offset = (int *) P_o;", + " int *q_offset = (int *) Q_o;", + "#else", + " short P_o[MAXPROC], P_o_tmp[MAXPROC+1];", + " short Q_o[MAXQ], Q_o_tmp[MAXPROC+1];", + "", + " short *proc_offset = (short *) P_o;", + " short *q_offset = (short *) Q_o;", + "#endif", + "uchar P_s[MAXPROC+1], P_s_tmp[MAXPROC+1];", + "uchar Q_s[MAXQ+1], Q_s_tmp[MAXQ+1];", + "uchar *proc_skip = (uchar *) P_s;", + "uchar *q_skip = (uchar *) Q_s;", + "", + "#ifdef TRIX", + " TRIX_v6 *freebodies;", + " TRIX_v6 *processes[MAXPROC+1];", + " TRIX_v6 *channels[MAXQ+1];", + " long _p_count[MAXPROC];", + " long _c_count[MAXPROC];", + "#endif\n", + "ulong vsize; /* vector size in bytes */", + "#ifdef SVDUMP", + " int vprefix=0, svfd; /* runtime option -pN */", + "#endif", + "char *tprefix = \"trail\"; /* runtime option -tsuffix */", + "short boq = -1; /* blocked_on_queue status */", + "int _; /* predefined write-only variable */", + "#ifdef PEG", + " long peg[NTRANS];", + "#endif", + 0, +}; +static const char *Preamble[] = { + "#ifdef RANDOMIZE", + " #define T_RAND RANDOMIZE", + "#endif", "#ifdef CNTRSTACK", - "#define onstack_now() (LL[trpt->j6] && LL[trpt->j7])", - "#define onstack_put() LL[trpt->j6]++; LL[trpt->j7]++", - "#define onstack_zap() LL[trpt->j6]--; LL[trpt->j7]--", + " #define onstack_now() (LL[trpt->j6] && LL[trpt->j7])", + " #define onstack_put() LL[trpt->j6]++; LL[trpt->j7]++", + " #define onstack_zap() LL[trpt->j6]--; LL[trpt->j7]--", "#endif", "#if !defined(SAFETY) && !defined(NOCOMP)", @@ -68,13 +103,13 @@ static char *Preamble[] = { * S_A remembers how many leading bytes in the sv * are used for these markers + fairness bits */ - "#define V_A (((now._a_t&1)?2:1) << (now._a_t&2))", - "#define A_V (((now._a_t&1)?1:2) << (now._a_t&2))", - "int S_A = 0;", + " #define V_A (((now._a_t&1)?2:1) << (now._a_t&2))", + " #define A_V (((now._a_t&1)?1:2) << (now._a_t&2))", + " int S_A = 0;", "#else", - "#define V_A 0", - "#define A_V 0", - "#define S_A 0", + " #define V_A 0", + " #define A_V 0", + " #define S_A 0", "#endif", "#ifdef MA", @@ -82,7 +117,7 @@ static char *Preamble[] = { "#undef onstack_put", "#undef onstack_zap", "#define onstack_put() ;", - "#define onstack_zap() gstore((char *) &now, vsize, 4)", + "#define onstack_zap() g_store((char *) &now, vsize, 4)", "#else", "#if defined(FULLSTACK) && !defined(BITSTATE)", "#define onstack_put() trpt->ostate = Lstate", @@ -93,165 +128,284 @@ static char *Preamble[] = { " }", "#endif", "#endif", - "struct H_el {", - " struct H_el *nxt;", - "#ifdef FULLSTACK", - " unsigned int tagged;", - "#if defined(BITSTATE) && !defined(NOREDUCE) && !defined(SAFETY)", - " unsigned int proviso;", /* uses just 1 bit 0/1 */ - "#endif", - "#endif", - "#if defined(CHECK) || (defined(COLLAPSE) && !defined(FULLSTACK))", - " unsigned long st_id;", - "#endif", - "#ifdef COLLAPSE", - "#if VECTORSZ<65536", - " unsigned short ln;", /* length of vector */ - "#else", - " unsigned long ln;", /* length of vector */ - "#endif", - "#endif", - "#if !defined(SAFETY) || defined(REACH)", - " unsigned int D;", - "#endif", - " unsigned state;", - "} **H_tab, **S_Tab;\n", - - "typedef struct Trail {", - " int st; /* current state */", - " uchar pr; /* process id */", - " uchar tau; /* 8 bit-flags */", - " uchar o_pm; /* 8 more bit-flags */", - "#if 0", - " Meaning of bit-flags:", - " tau&1 -> timeout enabled", - " tau&2 -> request to enable timeout 1 level up (in claim)", - " tau&4 -> current transition is a claim move", - " tau&8 -> current transition is an atomic move", - " tau&16 -> last move was truncated on stack", - " tau&32 -> current transition is a preselected move", - " tau&64 -> at least one next state is not on the stack", - " tau&128 -> current transition is a stutter move", - - " o_pm&1 -> the current pid moved -- implements else", - " o_pm&2 -> this is an acceptance state", - " o_pm&4 -> this is a progress state", - " o_pm&8 -> fairness alg rule 1 undo mark", - " o_pm&16 -> fairness alg rule 3 undo mark", - " o_pm&32 -> fairness alg rule 2 undo mark", - " o_pm&64 -> the current proc applied rule2", - " o_pm&128 -> a fairness, dummy move - all procs blocked", - "#endif", - "#if defined(FULLSTACK) && defined(MA) && !defined(BFS)", - " uchar proviso;", - "#endif", - "#ifndef BFS", - " uchar o_n, o_ot; /* to save locals */", - "#endif", - " uchar o_m;", - "#ifdef EVENT_TRACE", - "#if nstates_event<256", - " uchar o_event;", - "#else", - " unsigned short o_event;", - "#endif", - "#endif", - " 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)) || defined(BFS)", - " struct H_el *ostate; /* pointer to stored state */", - "#endif", - /* 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 */ - " } bup;", - "} Trail;", + "H_el **H_tab, **S_Tab;", + "/* #ifndef BFS_PAR */", + " H_el *Lstate;", + "/* #endif */", "Trail *trail, *trpt;", - "FILE *efd;", "uchar *this;", "long maxdepth=10000;", "long omaxdepth=10000;", + "#ifdef BCS", + " /* bitflags in trpt->bcs */", + " #define B_PHASE1 1", + " #define B_PHASE2 2", + " #define B_FORCED 4", + "int sched_max = 0;", + "#endif", + "", + "double quota; /* time limit */", + "#if NCORE>1", + " long z_handoff = -1;", + "#endif", "#ifdef SC", /* stack cycling */ - "char *stackfile;", + " char *stackfile;", "#endif", "uchar *SS, *LL;", + "", + "uchar reversing = 0;", "uchar HASH_NR = 0;", "", "double memcnt = (double) 0;", - "double memlim = (double) (1<<30);", + "double memlim = (double) (1<<30); /* 1 GB */", + "#if NCORE>1", + "double mem_reserved = (double) 0;", + "#endif", "", "/* for emalloc: */", "static char *have;", "static long left = 0L;", "static double fragment = (double) 0;", - "static unsigned long grow;", + "static ulong grow;", "", +#if 1 + "unsigned int HASH_CONST[] = {", + " /* generated by hashgen 421 -- assumes 4 bytes per int */", + " 0x100d4e63, 0x0fc22f87, 0xa7155c77, 0x78f2c3b9,", + " 0xde32d207, 0xc27d305b, 0x1bb3fb2b, 0x2798c7a5,", + " 0x9c675ffd, 0x777d9081, 0x07aef2f1, 0xae08922f,", + " 0x5bd365b7, 0xed51c47b, 0x9b5aeea1, 0xbcc9d431,", + " 0x396d8fff, 0xa2fd1367, 0x08616521, 0x5e84991f,", + " 0x87495bc5, 0x2930039b, 0xceb6a593, 0xfe522d63,", + " 0x7ff60baf, 0xf89b1fbf, 0x74c01755, 0xe0c559bf,", + " 0x3669fc47, 0x8756d3bf, 0x14f78445, 0x24c41779,", + " 0x0af7b129, 0xde22368d, 0x3e1c01e3, 0xaf773e49,", + " 0x5b762459, 0x86d12911, 0x0953a3af, 0xb66dc23d,", + " 0x96b3bd4f, 0x19b1dd51, 0xd886fbc3, 0xa7f3a025,", + " 0xccb48e63, 0x87d8f027, 0x2bea270d, 0xdb0e9379,", + " 0x78c09f21, 0x0cbbfe07, 0xea4bc7c3, 0x5bfbc3c9,", + " 0x3c6e53fd, 0xab320cdd, 0x31041409, 0x416e7485,", + " 0xe41d75fd, 0xc3c5060f, 0x201a9dc1, 0x93dee72b,", + " 0x6461305f, 0xc571dec5, 0xa1fd21c5, 0xfb421ce1,", + " 0x7f024b05, 0xfa518819, 0x6c9777fb, 0x0d4d9351,", + " 0x08b33861, 0xccb9d0f3, 0x34112791, 0xe962d7c9,", + " 0x8d742211, 0xcd9c47a1, 0x64437b69, 0x5fe40feb,", + " 0x806113cb, 0x10e1d593, 0x821851b3, 0x057a1ff3,", + " 0x8ededc0b, 0x90dd5b31, 0x635ff359, 0x68dbcd35,", + " 0x1050ff4f, 0xdbb07257, 0x486336db, 0x83af1e75,", + " 0x432f1799, 0xc1d0e7e7, 0x21f4eb5b, 0x881ec2c1,", + " 0x23f3b539, 0x6cdfb80d, 0x71d474cf, 0x97d5d4a9,", + " 0xf721d2e5, 0xb5ff3711, 0x3f2e58cd, 0x4e06e3d9,", + " 0x7d711739, 0x927887df, 0x7d57ad71, 0x232eb767,", + " 0xe3f5cc51, 0x6576b443, 0xed17bf1f, 0x8828b637,", + " 0xc940f6ab, 0xc7b830ef, 0x11ed8a13, 0xaff20949,", + " 0xf28a8465, 0x0da10cf9, 0xb512497d, 0x44accae1,", + " 0x95e0929f, 0xe08c8901, 0xfd22d6c9, 0xb6a5c029,", + " 0xaadb428d, 0x6e8a453d, 0x3d5c0195, 0x8bf4ae39,", + " 0xbf83ab19, 0x3e9dac33, 0xc4df075d, 0x39472d71,", + " 0xb8647725, 0x1a6d4887, 0x78a03577, 0xafd76ef7,", + " 0xc1a1d6b3, 0x1afb33c5, 0x87896299, 0x5cc992ef,", + " 0x7f805d0d, 0x089a039b, 0xa353cc27, 0x57b296b3,", + " 0x52badec9, 0xc916e431, 0x09171957, 0x14996d51,", + " 0xe87e32c7, 0xb4fdbb5d, 0xdd216a03, 0x4ddd3fff,", + " 0x767d5c57, 0x79c97509, 0xab70543b, 0xc5feca4f,", + " 0x8eb37b89, 0x20a2cefd, 0xf4b00b91, 0xf166593d,", + " 0x7bf50f65, 0x753e6c8b, 0xfb5b81dd, 0xf2d45ef5,", + " 0x9741c04f, 0x300da48d, 0x01dc4121, 0xa112cd47,", + " 0x0223b24b, 0xa89fbce7, 0x681e1f7b, 0xe7c6aedf,", + " 0x1fd3d523, 0x561ba723, 0xf54042fb, 0x1a516751,", + " 0xcd085bd5, 0xe74246d5, 0x8b170b5d, 0x249985e9,", + " 0x5b4d9cf7, 0xe9912323, 0x5fc0f339, 0x41f8f051,", + " 0x8a296fb1, 0x62909f51, 0x2c05d695, 0x095efccb,", + " 0xa91574f1, 0x0f5cc6c3, 0x23a2ca2b, 0xc6053ec1,", + " 0xeb19e081, 0x3d1b3997, 0xb0c5f3cd, 0xe5d85b35,", + " 0x1cb1bdf1, 0x0c8f278f, 0x518249c3, 0x9f61b68d,", + " 0xade0919d, 0x779e29c3, 0xdbac9485, 0x2ce149a9,", + " 0x254c2409, 0x205b34fb, 0xc8ab1a89, 0x6b4a2585,", + " 0x2303d94b, 0x8fa186b9, 0x49826da5, 0xd23a37ad,", + " 0x680b18c9, 0xa46fbd7f, 0xe42c2cf9, 0xf7cfcb5f,", + " 0xb4842b8b, 0xe483780d, 0x66cf756b, 0x3eb73781,", + " 0x41ca17a5, 0x59f91b0f, 0x92fb67d9, 0x0a5c330f,", + " 0x46013fdb, 0x3b0634af, 0x9024f533, 0x96a001a7,", + " 0x15bcd793, 0x3a311fb1, 0x78913b8b, 0x9d4a5ddf,", + " 0x33189b31, 0xa99e8283, 0xf7cb29e9, 0x12d64a27,", + " 0xeda770ff, 0xa7320297, 0xbd3c14a5, 0x96d0156f,", + " 0x0115db95, 0x7f79f52b, 0xa6d52521, 0xa063d4bd,", + " 0x9cb5e039, 0x42cf8195, 0xcb716835, 0x1bc21273,", + " 0x5a67ad27, 0x4b3b0545, 0x162cda67, 0x0489166b,", + " 0x85fd06a9, 0x562b037d, 0x995bc1f3, 0xe144e78b,", + " 0x1e749f69, 0xa36df057, 0xcfee1667, 0x8c4116b7,", + " 0x94647fe3, 0xe6899df7, 0x6d218981, 0xf1069079,", + " 0xd1851a33, 0xf424fc83, 0x24467005, 0xad8caf59,", + " 0x1ae5da13, 0x497612f9, 0x10f6d1ef, 0xeaf4ff05,", + " 0x405f030b, 0x693b041d, 0x2065a645, 0x9fec71b3,", + " 0xc3bd1b0f, 0xf29217a3, 0x0f25e15d, 0xd48c2b97,", + " 0xce8acf2d, 0x0629489b, 0x1a5b0e01, 0x32d0c059,", + " 0x2d3664bf, 0xc45f3833, 0xd57f551b, 0xbdd991c5,", + " 0x9f97da9f, 0xa029c2a9, 0x5dd0cbdf, 0xe237ba41,", + " 0x62bb0b59, 0x93e7d037, 0x7e495619, 0x51b8282f,", + " 0x853e8ef3, 0x9b8abbeb, 0x055f66f9, 0x2736f7e5,", + " 0x8d7e6353, 0x143abb65, 0x4e2bb5b3, 0x872e1adf,", + " 0x8fcac853, 0xb7cf6e57, 0x12177f3d, 0x1d2da641,", + " 0x07856425, 0xc0ed53dd, 0x252271d9, 0x79874843,", + " 0x0aa8c9b5, 0x7e804f93, 0x2d080e09, 0x3929ddfd,", + " 0x36433dbd, 0xd6568c17, 0xe624e939, 0xb33189ef,", + " 0x29e68bff, 0x8aae2433, 0xe6335499, 0xc5facd9d,", + " 0xbd5afc65, 0x7a584fa7, 0xab191435, 0x64bbdeef,", + " 0x9f5cd8e1, 0xb3a1be05, 0xbd0c1753, 0xb00e2c7f,", + " 0x6a96e315, 0x96a31589, 0x660af5af, 0xc0438d43,", + " 0x17637373, 0x6460e8df, 0x7d458de9, 0xd76b923f,", + " 0x316f045f, 0x3ccbd035, 0x63f64d81, 0xd990d969,", + " 0x7c860a93, 0x99269ff7, 0x6fbcac8f, 0xd8cc562b,", + " 0x67141071, 0x09f85ea3, 0x1298f2dd, 0x41fa86e5,", + " 0xce1d7cf5, 0x6b232c9d, 0x8f093d4b, 0x3203ad4b,", + " 0x07d70d5f, 0x38c44c75, 0x0887c9ef, 0x1833acf5,", + " 0xa3607f85, 0x7d367573, 0x0ea4ffc3, 0xad2d09c1,", + " 0x7a1e664f, 0xef41dff5, 0x03563491, 0x67f30a1f,", + " 0x5ce5f9ef, 0xa2487a27, 0xe5077957, 0x9beb36fd,", + " 0x16e41251, 0x216799ef, 0x07181f8d, 0xc191c3cf,", + " 0xba21cab5, 0x73944eb7, 0xdf9eb69d, 0x5fef6cfd,", + " 0xd750a6f5, 0x04f3fa43, 0x7cb2d063, 0xd3bdb369,", + " 0x35f35981, 0x9f294633, 0x5e293517, 0x70e51d05,", + " 0xf8db618d, 0x66ee05db, 0x835eaa77, 0x166a02c3,", + " 0xb516f283, 0x94102293, 0x1ace50a5, 0x64072651,", + " 0x66df7b75, 0x02e1b261, 0x8e6a73b9, 0x19dddfe7,", + " 0xd551cf39, 0x391c17cb, 0xf4304de5, 0xcd67b8d1,", + " 0x25873e8d, 0x115b4c71, 0x36e062f3, 0xaec0c7c9,", + " 0xd929f79d, 0x935a661b, 0xda762b47, 0x170bd76b,", + " 0x1a955cb5, 0x341fb0ef, 0x7f366cef, 0xc98f60c7,", + " 0xa4181af3, 0xa94a8837, 0x5fa3bc43, 0x11c638c1,", + " 0x4e66fabb, 0x30ab85cf, 0x250704ef, 0x8bf3bc07,", + " 0x6d2cd5ab, 0x613ef9c3, 0xb8e62149, 0x0404fd91,", + " 0xa04fd9b1, 0xa5e389eb, 0x9543bd23, 0xad6ca1f9,", + " 0x210c49ab, 0xf8e9532b, 0x854fba89, 0xdc7fc6bb,", + " 0x48a051a7, 0x6b2f383b, 0x61a4b433, 0xd3af231b,", + " 0xc5023fc7, 0xa5aa85df, 0xa0cd1157, 0x4206f64d,", + " 0x3fea31c3, 0x62d510a1, 0x13988957, 0x6a11a033,", + " 0x46f2a3b7, 0x2784ef85, 0x229eb9eb, 0x9c0c3053,", + " 0x5b7ead39, 0x82ae9afb, 0xf99e9fb3, 0x914b6459,", + " 0xaf05edd7, 0xc82710dd, 0x8fc1ea1f, 0x7e0d7a8d,", + " 0x7c7592e9, 0x65321017, 0xea57553f, 0x4aeb49ff,", + " 0x5239ae4d, 0x4b4b4585, 0x94091c21, 0x7eaaf4cb,", + " 0x6b489d6f, 0xecb9c0c3, 0x29a7af63, 0xaf117a0d,", + " 0x969ea6cd, 0x7658a34d, 0x5fc0bba9, 0x26e99b7f,", + " 0x7a6f260f, 0xe37c34f1, 0x1a1569bb, 0xc3bc7371,", + " 0x8567543d, 0xad0c46a9, 0xa1264fd9, 0x16f10b29,", + " 0x5e00dd3b, 0xf85b6bcd, 0xa2d32d8b, 0x4a3c8d43,", + " 0x6b33b959, 0x4fd1e6c9, 0x7938b8a9, 0x1ec795c7,", + " 0xe2ef3409, 0x83c16b9d, 0x0d3fd9eb, 0xeb461ad7,", + " 0xb09c831d, 0xaf052001, 0x7911164d, 0x1a9dc191,", + " 0xb52a0815, 0x0f732157, 0xc68c4831, 0x12cf3cbb };", +#else "unsigned int HASH_CONST[] = {", " /* asuming 4 bytes per int */", - " 0x88888EEF, 0x00400007,", - " 0x04c11db7, 0x100d4e63,", - " 0x0fc22f87, 0x3ff0c3ff,", - " 0x38e84cd7, 0x02b148e9,", - " 0x98b2e49d, 0xb616d379,", - " 0xa5247fd9, 0xbae92a15,", - " 0xb91c8bc5, 0x8e5880f3,", - " 0xacd7c069, 0xb4c44bb3,", - " 0x2ead1fb7, 0x8e428171,", - " 0xdbebd459, 0x828ae611,", - " 0x6cb25933, 0x86cdd651,", - " 0x9e8f5f21, 0xd5f8d8e7,", - " 0x9c4e956f, 0xb5cf2c71,", - " 0x2e805a6d, 0x33fc3a55,", - " 0xaf203ed1, 0xe31f5909,", - " 0x5276db35, 0x0c565ef7,", - " 0x273d1aa5, 0x8923b1dd,", - " 0", - "};", - "int mreached=0, done=0, errors=0, Nrun=1;", + " 0x100d4e63, 0x0fc22f87,", + " 0x3ff0c3ff, 0x38e84cd7,", + " 0x02b148e9, 0x98b2e49d,", + " 0xb616d379, 0xa5247fd9,", + " 0xbae92a15, 0xb91c8bc5,", + " 0x8e5880f3, 0xacd7c069,", + " 0xb4c44bb3, 0x2ead1fb7,", + " 0x8e428171, 0xdbebd459,", + " 0x00400007, 0x04c11db7,", + " 0x828ae611, 0x6cb25933,", + " 0x86cdd651, 0x9e8f5f21,", + " 0xd5f8d8e7, 0x9c4e956f,", + " 0xb5cf2c71, 0x2e805a6d,", + " 0x33fc3a55, 0xaf203ed1,", + " 0xe31f5909, 0x5276db35,", + " 0x0c565ef7, 0x273d1aa5,", + " 0x8923b1dd, 0xa9acaac5,", + " 0xd1f69207, 0xedfd944b,", + " 0x9a68e46b, 0x5355e13f,", + " 0x7eeb44f9, 0x932beea9,", + " 0x330c4cd3, 0x87f34e5f,", + " 0x1b5851b7, 0xb9ca6447,", + " 0x58f96a8f, 0x1b3b5307,", + " 0x31c387b3, 0xf35f0f35,", + " 0xa0acc4df, 0xf3140303,", + " 0x2446245d, 0xe4b8f4ef,", + " 0x5c007383, 0x68e648af,", + " 0x1814fba7, 0xcdf731b5,", + " 0xd09ccb4b, 0xb92d0eff,", + " 0xcc3c6b67, 0xd3af6a57,", + " 0xf44fc3f5, 0x5bb67623,", + " 0xaeb9c953, 0x5e0ac739,", + " 0x3a7fda09, 0x5edf39eb,", + " 0x661eefd9, 0x6423f0d1,", + " 0x910fe413, 0x9ec92297,", + " 0x4bd8159d, 0xa7b16ee1,", + " 0x89d484e9, 0x7f305cb3,", + " 0xc5f303e7, 0x415deeef,", + " 0x09986f89, 0x7e9c4117,", + " 0x0b7cbedb, 0xf9ed7561,", + " 0x7a20ac99, 0xf05adef3,", + " 0x5893d75b, 0x44d73327,", + " 0xb583c873, 0x324d2145,", + " 0x7fa3829b, 0xe4b47a23,", + " 0xe256d94f, 0xb1fd8959,", + " 0xe561a321, 0x1435ac09,", + " 0xdd62408b, 0x02ec0bcb,", + " 0x5469b785, 0x2f4f50bb,", + " 0x20f19395, 0xf96ba085,", + " 0x2381f937, 0x768e2a11 };", +#endif + "", + "#if NCORE>1", + "extern int core_id;", + "#endif", + "long mreached=0;", + "int done=0, errors=0, Nrun=1;", + "int c_init_done=0;", + "char *c_stack_start = (char *) 0;", "double nstates=0, nlinks=0, truncs=0, truncs2=0;", "double nlost=0, nShadow=0, hcmp=0, ngrabs=0;", + "#ifdef BFS_PAR", + "extern ulong bfs_punt;", + "#endif", + "#ifdef PUTPID", + "char *progname;", + "#endif", + "#if defined(ZAPH) && defined(BITSTATE)", + "double zstates = 0;", + "#endif", + "/* int c_init_run; */", + "#ifdef REVERSE", + " #define P_REVERSE", + "#endif", + "#ifdef T_REVERSE", + " int t_reverse = 1;", /* can be modified with a parameter */ + "#else", + " int t_reverse = 0;", + "#endif", "#ifdef BFS", "double midrv=0, failedrv=0, revrv=0;", "#endif", - "unsigned long nr_states=0; /* nodes in DFA */", + "ulong 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;", "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, silent = 0;", + "int gui = 0, coltrace = 0, readtrail = 0;", + "int whichtrail = 0, whichclaim = -1, onlyproc = -1, silent = 0;", + "char *claimname;", "#endif", - "int state_tables=0, fairness=0, no_rck=0, Nr_Trails=0;", - "char simvals[128];", + "int state_tables=0, fairness=0, no_rck=0, Nr_Trails=0, dodot=0;", + "char simvals[256];", "#ifndef INLINE", "int TstOnly=0;", "#endif", - "unsigned long mask, nmask;", + "ulong mask, nmask;", "#ifdef BITSTATE", - "int ssize=23; /* 1 Mb */", + "int ssize=27; /* 16 Mb */", "#else", - "int ssize=19; /* 512K slots */", + "int ssize=24; /* 16M slots */", "#endif", "int hmax=0, svmax=0, smax=0;", "int Maxbody=0, XX;", - "uchar *noptr; /* used by macro Pptr(x) */", + "uchar *noptr, *noqptr; /* used by Pptr(x) and Qptr(x) */", "#ifdef VAR_RANGES", "void logval(char *, int);", "void dumpranges(void);", @@ -260,36 +414,55 @@ static char *Preamble[] = { "#ifdef MA", "#define INLINE_REV", "extern void dfa_init(unsigned short);", - "extern int dfa_member(unsigned long);", + "extern int dfa_member(ulong);", "extern int dfa_store(uchar *);", "unsigned int maxgs = 0;", "#endif", - - "State comp_now; /* compressed state vector */", - "State comp_msk;", - "uchar *Mask = (uchar *) &comp_msk;", - "#ifdef COLLAPSE", - "State comp_tmp;", - "static char *scratch = (char *) &comp_tmp;", + "", + "#ifdef ALIGNED", + " State comp_now __attribute__ ((aligned (8)));", + " /* gcc 64-bit aligned for Itanium2 systems */", + " /* MAJOR runtime penalty if not used on those systems */", + "#else", + " State comp_now; /* compressed state vector */", "#endif", - - "Stack *stack; /* for queues, processes */", + "", + "#ifndef HC", + " #ifdef BFS_PAR", + " State tmp_msk;", + " #endif", + " State comp_msk;", + " uchar *Mask = (uchar *) &comp_msk;", + "#endif", + "#ifdef COLLAPSE", + " State comp_tmp;", + " static char *scratch = (char *) &comp_tmp;", + "#endif", + "", + "_Stack *stack; /* for queues, processes */", "Svtack *svtack; /* for old state vectors */", "#ifdef BITSTATE", - "static unsigned hfns = 3; /* new default */", + "static unsigned int hfns = 3; /* new default */", "#endif", - "static unsigned long j1;", - "static unsigned long K1, K2;", - "static unsigned long j2, j3, j4;", + "static ulong j1_spin, j2_spin; /* 5.2.1: avoid nameclash with math.h */", + "static ulong j3_spin, j4_spin;", + "ulong K1, K2;", "#ifdef BITSTATE", -#ifndef POWOW - "static long udmem;", -#endif + "long udmem;", "#endif", + "#ifndef BFS_PAR", "static long A_depth = 0;", - "long depth = 0;", /* not static to support -S2 option, but possible clash with embedded code */ - "static uchar warned = 0, iterative = 0, like_java = 0, every_error = 0;", - "static uchar noasserts = 0, noends = 0, bounded = 0;", + "#endif", + "long depth = 0;", + "long depthfound = -1; /* loop detection */", + /* depth: not static to support -S2, but possible clash with embedded code */ + "#if NCORE>1", + "long nr_handoffs = 0;", + "#endif", + "uchar warned = 0, iterative = 0, exclusive = 0, like_java = 0, every_error = 0;", + "uchar noasserts = 0, noends = 0, bounded = 0;", + "uint s_rand = 12345; /* default seed */", + "#if SYNC>0 && ASYNC==0", "void set_recvs(void);", "int no_recvs(int);", @@ -302,17 +475,32 @@ static char *Preamble[] = { "#define UnBlock /* don't bother */", "#endif\n", "#ifdef BITSTATE", - "int (*bstore)(char *, int);", + "int (*b_store)(char *, int);", "int bstore_reg(char *, int);", -#ifndef POWOW "int bstore_mod(char *, int);", -#endif "#endif", + "", + "void dfs_uerror(char *);", + "void dfs_Uerror(char *);", + "#ifdef BFS_PAR", + "void bfs_uerror(char *);", + "void bfs_Uerror(char *);", + "#endif", + "void (*uerror)(char *);", + "void (*Uerror)(char *);", + "void (*hasher)(uchar *, int);", + "void (*o_hash)(uchar *, int, int);", + "void d_hash(uchar *, int);", + "void m_hash(uchar *, int);", + "void d_sfh(uchar *, int);", + "void o_hash32(uchar *, int, int);", + "void o_hash64(uchar *, int, int);", + "", "void active_procs(void);", "void cleanup(void);", "void do_the_search(void);", "void find_shorter(int);", - "void iniglobals(void);", + "void iniglobals(int);", "void stopped(int);", "void wrapup(void);", "int *grab_ints(int);", @@ -320,7 +508,7 @@ static char *Preamble[] = { 0, }; -static char *Tail[] = { +static const char *Tail[] = { "Trans *", "settr( int t_id, int a, int b, int c, int d,", " char *t, int g, int tpe0, int tpe1)", @@ -425,10 +613,14 @@ static char *Tail[] = { "}", "#endif", "void", - "retrans(int n, int m, int is, short srcln[], uchar reach[])", + "retrans(int n, int m, int is, short srcln[], uchar reach[], uchar lpstate[])", " /* process n, with m states, is=initial state */", "{ Trans *T0, *T1, *T2, *T3;", - " int i, k;", + " Trans *T4, *T5; /* t_reverse or has_unless */", + " int i;", + "#if defined(HAS_UNLESS) || !defined(NOREDUCE)", + " int k;", + "#endif", "#ifndef NOREDUCE", " int g, h, j, aa;", "#endif", @@ -436,7 +628,7 @@ static char *Tail[] = { " int p;", "#endif", " if (state_tables >= 4)", - " { printf(\"STEP 1 proctype %%s\\n\", ", + " { printf(\"STEP 1 %%s\\n\", ", " procname[n]);", " for (i = 1; i < m; i++)", " for (T0 = trans[n][i]; T0; T0 = T0->nxt)", @@ -477,7 +669,7 @@ static char *Tail[] = { " } while (cnt);", " if (state_tables >= 3)", - " { printf(\"STEP 2 proctype %%s\\n\", ", + " { printf(\"STEP 2 %%s\\n\", ", " procname[n]);", " for (i = 1; i < m; i++)", " for (T0 = trans[n][i]; T0; T0 = T0->nxt)", @@ -490,7 +682,9 @@ static char *Tail[] = { "#if 0", " printf(\"\\t\\tpull %%d (%%d) to %%d\\n\",", " T1->st, T1->forw, i);", - "#endif", + "#endif", /* pull linenumber ref as well: */ + " srcln[i] = srcln[T1->st]; /* Oyvind Teig, 5.2.0 */", + "", " if (!trans[n][T1->st]) continue;", " T0 = cpytr(trans[n][T1->st]);", " trans[n][i] = T0;", @@ -502,6 +696,7 @@ static char *Tail[] = { " printf(\"\\t\\tpull %%d (%%d) to %%d\\n\",", " T1->st, T1->forw, i);", "#endif", + " /* srcln[i] = srcln[T1->st]; gh: not useful */", " if (!trans[n][T1->st]) continue;", " T0->nxt = cpytr(trans[n][T1->st]);", " T0 = T0->nxt;", @@ -509,7 +704,7 @@ static char *Tail[] = { " imed(T0, T1->st, n, i);", " } } }", " if (state_tables >= 2)", - " { printf(\"STEP 3 proctype %%s\\n\", ", + " { printf(\"STEP 3 %%s\\n\", ", " procname[n]);", " for (i = 1; i < m; i++)", " for (T0 = trans[n][i]; T0; T0 = T0->nxt)", @@ -525,8 +720,8 @@ static char *Tail[] = { " * and prepend them to the transition-", " * list of state i", " */", - " if (!like_java) /* the default */", - " { for (T0 = trans[n][i]; T0; T0 = T0->nxt)", + " if (!like_java) /* the default */", + " { for (T0 = trans[n][i]; T0; T0 = T0->nxt)", " for (k = HAS_UNLESS-1; k >= 0; k--)", " { if (p = T0->escp[k])", " for (T1 = trans[n][p]; T1; T1 = T1->nxt)", @@ -537,9 +732,8 @@ static char *Tail[] = { " T2->nxt = trans[n][i];", " trans[n][i] = T2;", " } }", - " } else /* outermost unless checked first */", - " { Trans *T4;", - " T4 = T3 = (Trans *) 0;", + " } else /* outermost unless checked first */", + " { T4 = T3 = (Trans *) 0;", " for (T0 = trans[n][i]; T0; T0 = T0->nxt)", " for (k = HAS_UNLESS-1; k >= 0; k--)", " { if (p = T0->escp[k])", @@ -557,22 +751,21 @@ static char *Tail[] = { " { T3->nxt = trans[n][i];", " trans[n][i] = T4;", " }", - " }", + " }", " }", "#endif", "#ifndef NOREDUCE", " for (i = 1; i < m; i++)", - " {", - " if (a_cycles)", + " { if (a_cycles)", " { /* moves through these states are visible */", - "#if PROG_LAB>0 && defined(HAS_NP)", + " #if PROG_LAB>0 && defined(HAS_NP)", " if (progstate[n][i])", " goto degrade;", " for (T1 = trans[n][i]; T1; T1 = T1->nxt)", " if (progstate[n][T1->st])", " goto degrade;", - "#endif", + " #endif", " if (accpstate[n][i] || visstate[n][i])", " goto degrade;", " for (T1 = trans[n][i]; T1; T1 = T1->nxt)", @@ -668,19 +861,44 @@ static char *Tail[] = { " continue;", " stopstate[n][T2->st] = 1;", " }", - " if (state_tables)", - " { printf(\"proctype \");", - " if (!strcmp(procname[n], \":init:\"))", - " printf(\"init\\n\");", - " else", - " printf(\"%%s\\n\", procname[n]);", + " if (state_tables && !verbose)", + " { if (dodot)", + " { char buf[256], *q = buf, *p = procname[n];", + " while (*p != '\\0')", + " { if (*p != ':')", + " { *q++ = *p;", + " }", + " p++;", + " }", + " *q = '\\0';", + " printf(\"digraph \");", + " switch (Btypes[n]) {", + " case I_PROC: printf(\"init {\\n\"); break;", + " case N_CLAIM: printf(\"claim_%%s {\\n\", buf); break;", + " case E_TRACE: printf(\"notrace {\\n\"); break;", + " case N_TRACE: printf(\"trace {\\n\"); break;", + " default: printf(\"p_%%s {\\n\", buf); break;", + " }", + " printf(\"size=\\\"8,10\\\";\\n\");", + " printf(\" GT [shape=box,style=dotted,label=\\\"%%s\\\"];\\n\", buf);", + " printf(\" GT -> S%%d;\\n\", is);", + " } else", + " { switch (Btypes[n]) {", + " case I_PROC: printf(\"init\\n\"); break;", + " case N_CLAIM: printf(\"claim %%s\\n\", procname[n]); break;", + " case E_TRACE: printf(\"notrace assertion\\n\"); break;", + " case N_TRACE: printf(\"trace assertion\\n\"); break;", + " default: printf(\"proctype %%s\\n\", procname[n]); break;", + " } }", " for (i = 1; i < m; i++)", - " reach[i] = 1;", + " { reach[i] = 1;", + " }", " tagtable(n, m, is, srcln, reach);", + " if (dodot) printf(\"}\\n\");", " } else", " for (i = 1; i < m; i++)", " { int nrelse;", - " if (strcmp(procname[n], \":never:\") != 0)", + " if (Btypes[n] != N_CLAIM)", " { for (T0 = trans[n][i]; T0; T0 = T0->nxt)", " { if (T0->st == i", " && strcmp(T0->tp, \"(1)\") == 0)", @@ -703,16 +921,84 @@ static char *Tail[] = { " printf(\" 'else' stmnts\\n\");", " pan_exit(1);", " } }", - " if (!state_tables && strcmp(procname[n], \":never:\") == 0)", - " { int h = 0;", + "#if !defined(LOOPSTATE) && !defined(BFS_PAR)", + " if (state_tables)", + "#endif", + " do_dfs(n, m, is, srcln, reach, lpstate);", + "", + " if (!t_reverse)", + " { return;", + " }", + " /* process n, with m states, is=initial state -- reverse list */", + " if (!state_tables && Btypes[n] != N_CLAIM)", + " { for (i = 1; i < m; i++)", /* for each state */ + " { Trans *Tx = (Trans *) 0; /* list of escapes */", + " Trans *Ty = (Trans *) 0; /* its tail element */", + " T1 = (Trans *) 0; /* reversed list */", + " T2 = (Trans *) 0; /* its tail */", + " T3 = (Trans *) 0; /* remembers possible 'else' */", + "", + " /* find unless-escapes, they should go first */", + " T4 = T5 = T0 = trans[n][i];", + " #ifdef HAS_UNLESS", + " while (T4 && T4->e_trans) /* escapes are first in orig list */", + " { T5 = T4; /* remember predecessor */", + " T4 = T4->nxt;", + " }", + " #endif", + " /* T4 points to first non-escape, T5 to its parent, T0 to original list */", + " if (T4 != T0) /* there was at least one escape */", + " { T3 = T5->nxt; /* start of non-escapes */", + " T5->nxt = (Trans *) 0; /* separate */", + " Tx = T0; /* start of the escapes */", + " Ty = T5; /* its tail */", + " T0 = T3; /* the rest, to be reversed */", + " }", + " /* T0 points to first non-escape, Tx to the list of escapes, Ty to its tail */", + "", + " /* first tail-add non-escape transitions, reversed */", + " T3 = (Trans *) 0;", /* remember a possible 'else' */ + " for (T5 = T0; T5; T5 = T4)", + " { T4 = T5->nxt;", + " #ifdef HAS_UNLESS", + " if (T5->e_trans)", + " { printf(\"error: cannot happen!\\n\");", + " continue;", + " }", + " #endif", + " if (strcmp(T5->tp, \"else\") == 0)", + " { T3 = T5;", + " T5->nxt = (Trans *) 0;", + " } else", + " { T5->nxt = T1;", + " if (!T1) { T2 = T5; }", + " T1 = T5;", + " } }", + " /* T3 points to a possible else, which is removed from the list */", + " /* T1 points to the reversed list so far (without escapes) */", + " /* T2 points to the tail element -- where the else should go */", + " if (T2 && T3)", + " { T2->nxt = T3; /* add else */", + " } else", + " { if (T3) /* there was an else, but there's no tail */", + " { if (!T1) /* and no reversed list */", + " { T1 = T3; /* odd, but possible */", + " } else /* even stranger */", + " { T1->nxt = T3;", + " } } }", + "", + " /* add in the escapes, to that they appear at the front */", + " if (Tx && Ty) { Ty->nxt = T1; T1 = Tx; }", + "", + " trans[n][i] = T1;", + " /* reversed, with escapes first and else last */", + " } }", + " if (state_tables && verbose)", + " { printf(\"FINAL proctype %%s\\n\", ", + " procname[n]);", " for (i = 1; i < m; i++)", " for (T0 = trans[n][i]; T0; T0 = T0->nxt)", - " if (T0->forw > h) h = T0->forw;", - " h++;", - " frm_st0 = (short *) emalloc(h * sizeof(short));", - " for (i = 1; i < m; i++)", - " for (T0 = trans[n][i]; T0; T0 = T0->nxt)", - " frm_st0[T0->forw] = i;", + " crack(n, i, T0, srcln);", " }", "}", "void", @@ -731,7 +1017,12 @@ static char *Tail[] = { " reach[is] = 0;", " if (state_tables)", " for (z = trans[n][is]; z; z = z->nxt)", - " crack(n, is, z, srcln);", + " { if (dodot)", + " dot_crack(n, is, z);", + " else", + " crack(n, is, z, srcln);", + " }", + "", " for (z = trans[n][is]; z; z = z->nxt)", " {", "#ifdef HAS_UNLESS", @@ -747,6 +1038,47 @@ static char *Tail[] = { "#endif", " }", "}", + "", + "extern Trans *t_id_lkup[];", /* needed by BFS_PAR */ + "", + "void", + "dfs_table(int n, int m, int is, short srcln[], uchar reach[], uchar lpstate[])", + "{ Trans *z;\n", + " if (is >= m || is <= 0 || !trans[n][is])", + " return;", + " if ((reach[is] & (4|8|16)) != 0)", + " { if ((reach[is] & (8|16)) == 16) /* on stack, not yet recorded */", + " { lpstate[is] = 1;", + " reach[is] |= 8; /* recorded */", + " if (state_tables && verbose)", + " { printf(\"state %%d line %%d is a loopstate\\n\", is, srcln[is]);", + " } }", + " return;", + " }", + " reach[is] |= (4|16); /* visited | onstack */", + " for (z = trans[n][is]; z; z = z->nxt)", + " { t_id_lkup[z->t_id] = z;", /* needed by BFS_PAR */ + "#ifdef HAS_UNLESS", + " int i, j;", + "#endif", + " dfs_table(n, m, z->st, srcln, reach, lpstate);", + "#ifdef HAS_UNLESS", + " for (i = 0; i < HAS_UNLESS; i++)", + " { j = trans[n][is]->escp[i];", + " if (!j) break;", + " dfs_table(n, m, j, srcln, reach, lpstate);", + " }", + "#endif", + " }", + " reach[is] &= ~16; /* no longer on stack */", + "}", + "void", + "do_dfs(int n, int m, int is, short srcln[], uchar reach[], uchar lpstate[])", + "{ int i;", + " dfs_table(n, m, is, srcln, reach, lpstate);", + " for (i = 0; i < m; i++)", + " reach[i] &= ~(4|8|16);", + "}", "void", "crack(int n, int j, Trans *z, short srcln[])", "{ int i;\n", @@ -765,19 +1097,19 @@ static char *Tail[] = { " }", "#endif", " printf(\"]\");", - " printf(\" [%%s%%s%%s%%s%%s] line %%d => \",", + " printf(\" [%%s%%s%%s%%s%%s] %%s:%%d => \",", " z->atom&6?\"A\":z->atom&32?\"D\":\"-\",", " accpstate[n][j]?\"a\" :\"-\",", " stopstate[n][j]?\"e\" : \"-\",", " progstate[n][j]?\"p\" : \"-\",", " z->atom & 8 ?\"L\":\"G\",", - " srcln[j]);", + " PanSource, srcln[j]);", " for (i = 0; z->tp[i]; i++)", " if (z->tp[i] == \'\\n\')", " printf(\"\\\\n\");", " else", " putchar(z->tp[i]);", - " if (z->qu[0])", + " if (verbose && z->qu[0])", " { printf(\"\\t[\");", " for (i = 0; i < 6; i++)", " if (z->qu[i])", @@ -788,6 +1120,32 @@ static char *Tail[] = { " printf(\"\\n\");", " fflush(stdout);", "}", + "/* spin -a m.pml; cc -o pan pan.c; ./pan -D | dot -Tps > foo.ps; ps2pdf foo.ps */", + "void", + "dot_crack(int n, int j, Trans *z)", + "{ int i;\n", + " if (!z) return;", + " printf(\"\tS%%d -> S%%d [color=black\", j, z->st);", + "", + " if (z->atom&6) printf(\",style=dashed\");", /* A */ + " else if (z->atom&32) printf(\",style=dotted\");", /* D */ + " else if (z->atom&8) printf(\",style=solid\");", /* L */ + " else printf(\",style=bold\");", /* G */ + /* other styles: filled dotted */ + "", + " printf(\",label=\\\"\");", + " for (i = 0; z->tp[i]; i++)", + " { if (z->tp[i] == \'\\\\\'", + " && z->tp[i+1] == \'n\')", + " { i++; printf(\" \");", + " } else", + " { putchar(z->tp[i]);", + " } }", + " printf(\"\\\"];\\n\");", + " if (accpstate[n][j]) printf(\" S%%d [color=red,style=bold];\\n\", j);", + " else if (progstate[n][j]) printf(\" S%%d [color=green,style=bold];\\n\", j);", + " if (stopstate[n][j]) printf(\" S%%d [color=blue,style=bold,shape=box];\\n\", j);", + "}", "", "#ifdef VAR_RANGES", "#define BYTESIZE 32 /* 2^8 : 2^3 = 256:8 = 32 */", diff --git a/sys/src/cmd/spin/pangen3.c b/sys/src/cmd/spin/pangen3.c index 4feb80ab1..d59b455ff 100644 --- a/sys/src/cmd/spin/pangen3.c +++ b/sys/src/cmd/spin/pangen3.c @@ -1,22 +1,20 @@ /***** spin: pangen3.c *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #include "spin.h" #include "y.tab.h" +#include -extern FILE *th; -extern int claimnr, eventmapnr; +extern FILE *th, *tc; +extern int eventmapnr, old_priority_rules; typedef struct SRC { - short ln, st; /* linenr, statenr */ + int ln, st; /* linenr, statenr */ Symbol *fn; /* filename */ struct SRC *nxt; } SRC; @@ -28,16 +26,18 @@ static int lastfrom; static SRC *frst = (SRC *) 0; static SRC *skip = (SRC *) 0; +extern int ltl_mode; + extern void sr_mesg(FILE *, int, int); static void putnr(int n) { if (col++ == 8) - { fprintf(th, "\n\t"); + { fprintf(tc, "\n\t"); /* was th */ col = 1; } - fprintf(th, "%3d, ", n); + fprintf(tc, "%3d, ", n); /* was th */ } static void @@ -47,7 +47,7 @@ putfnm(int j, Symbol *s) return; if (lastfnm) - fprintf(th, "{ %s, %d, %d },\n\t", + fprintf(tc, "{ \"%s\", %d, %d },\n\t", /* was th */ lastfnm->name, lastfrom, j-1); @@ -59,73 +59,118 @@ static void putfnm_flush(int j) { if (lastfnm) - fprintf(th, "{ %s, %d, %d }\n", + fprintf(tc, "{ \"%s\", %d, %d }\n", /* was th */ lastfnm->name, lastfrom, j); } +static SRC * +newsrc(int m, SRC *n) +{ SRC *tmp; + tmp = (SRC *) emalloc(sizeof(SRC)); + tmp->st = m; + tmp->nxt = n; + return tmp; +} + void putskip(int m) /* states that need not be reached */ -{ SRC *tmp; - - for (tmp = skip; tmp; tmp = tmp->nxt) - if (tmp->st == m) - return; - tmp = (SRC *) emalloc(sizeof(SRC)); - tmp->st = (short) m; - tmp->nxt = skip; - skip = tmp; +{ SRC *tmp, *lst = (SRC *)0; + /* 6.4.0: now an ordered list */ + for (tmp = skip; tmp; lst = tmp, tmp = tmp->nxt) + { if (tmp->st == m) + { return; + } + if (tmp->st > m) /* insert before */ + { if (tmp == skip) + { tmp = newsrc(m, skip); + skip = tmp; + } else + { assert(lst); + tmp = newsrc(m, lst->nxt); + lst->nxt = tmp; + } + return; + } } + /* insert at the end */ + if (lst) + { lst->nxt = newsrc(m, 0); + } else /* empty list */ + { skip = newsrc(m, 0); + } } void unskip(int m) /* a state that needs to be reached after all */ -{ SRC *tmp, *lst=(SRC *)0; +{ SRC *tmp, *lst = (SRC *)0; for (tmp = skip; tmp; lst = tmp, tmp = tmp->nxt) - if (tmp->st == m) + { if (tmp->st == m) { if (tmp == skip) skip = skip->nxt; - else + else if (lst) /* always true, but helps coverity */ lst->nxt = tmp->nxt; break; } + if (tmp->st > m) + { break; /* m is not in list */ + } } } void putsrc(Element *e) /* match states to source lines */ -{ SRC *tmp; +{ SRC *tmp, *lst = (SRC *)0; int n, m; if (!e || !e->n) return; n = e->n->ln; m = e->seqno; - - for (tmp = frst; tmp; tmp = tmp->nxt) - if (tmp->st == m) + /* 6.4.0: now an ordered list */ + for (tmp = frst; tmp; lst = tmp, tmp = tmp->nxt) + { if (tmp->st == m) { if (tmp->ln != n || tmp->fn != e->n->fn) - printf("putsrc mismatch %d - %d, file %s\n", n, + printf("putsrc mismatch seqno %d, line %d - %d, file %s\n", m, n, tmp->ln, tmp->fn->name); return; } - tmp = (SRC *) emalloc(sizeof(SRC)); - tmp->ln = (short) n; - tmp->st = (short) m; + if (tmp->st > m) /* insert before */ + { if (tmp == frst) + { tmp = newsrc(m, frst); + frst = tmp; + } else + { assert(lst); + tmp = newsrc(m, lst->nxt); + lst->nxt = tmp; + } + tmp->ln = n; + tmp->fn = e->n->fn; + return; + } } + /* insert at the end */ + tmp = newsrc(m, lst?lst->nxt:0); + tmp->ln = n; tmp->fn = e->n->fn; - tmp->nxt = frst; - frst = tmp; + if (lst) + { lst->nxt = tmp; + } else + { frst = tmp; + } } static void dumpskip(int n, int m) { SRC *tmp, *lst; + FILE *tz = tc; /* was th */ int j; - fprintf(th, "uchar reached%d [] = {\n\t", m); + fprintf(tz, "uchar reached%d [] = {\n\t", m); + tmp = skip; + lst = (SRC *) 0; for (j = 0, col = 0; j <= n; j++) - { lst = (SRC *) 0; - for (tmp = skip; tmp; lst = tmp, tmp = tmp->nxt) - if (tmp->st == j) + { /* find j in the sorted list */ + for ( ; tmp; lst = tmp, tmp = tmp->nxt) + { if (tmp->st == j) { putnr(1); if (lst) lst->nxt = tmp->nxt; @@ -133,12 +178,17 @@ dumpskip(int n, int m) skip = tmp->nxt; break; } + if (tmp->st > j) + { putnr(0); + break; /* j is not in the list */ + } } + if (!tmp) - putnr(0); - } - fprintf(th, "};\n"); - if (m == claimnr) - fprintf(th, "#define reached_claim reached%d\n", m); + { putnr(0); + } } + fprintf(tz, "};\n"); + fprintf(tz, "uchar *loopstate%d;\n", m); + if (m == eventmapnr) fprintf(th, "#define reached_event reached%d\n", m); @@ -149,27 +199,34 @@ void dumpsrc(int n, int m) { SRC *tmp, *lst; int j; + static int did_claim = 0; + FILE *tz = tc; /* was th */ - fprintf(th, "short src_ln%d [] = {\n\t", m); + fprintf(tz, "\nshort src_ln%d [] = {\n\t", m); + tmp = frst; for (j = 0, col = 0; j <= n; j++) - { lst = (SRC *) 0; - for (tmp = frst; tmp; lst = tmp, tmp = tmp->nxt) - if (tmp->st == j) + { for ( ; tmp; tmp = tmp->nxt) + { if (tmp->st == j) { putnr(tmp->ln); break; } + if (tmp->st > j) + { putnr(0); + break; + } } if (!tmp) - putnr(0); - } - fprintf(th, "};\n"); + { putnr(0); + } } + fprintf(tz, "};\n"); lastfnm = (Symbol *) 0; - lastdef.name = "\"-\""; - fprintf(th, "S_F_MAP src_file%d [] = {\n\t", m); + lastdef.name = "-"; + fprintf(tz, "S_F_MAP src_file%d [] = {\n\t", m); + tmp = frst; + lst = (SRC *) 0; for (j = 0, col = 0; j <= n; j++) - { lst = (SRC *) 0; - for (tmp = frst; tmp; lst = tmp, tmp = tmp->nxt) - if (tmp->st == j) + { for ( ; tmp; lst = tmp, tmp = tmp->nxt) + { if (tmp->st == j) { putfnm(j, tmp->fn); if (lst) lst->nxt = tmp->nxt; @@ -177,14 +234,20 @@ dumpsrc(int n, int m) frst = tmp->nxt; break; } + if (tmp->st > j) + { putfnm(j, &lastdef); + break; + } } if (!tmp) - putfnm(j, &lastdef); - } + { putfnm(j, &lastdef); + } } putfnm_flush(j); - fprintf(th, "};\n"); + fprintf(tz, "};\n"); - if (m == claimnr) - fprintf(th, "#define src_claim src_ln%d\n", m); + if (pid_is_claim(m) && !did_claim) + { fprintf(tz, "short *src_claim;\n"); + did_claim++; + } if (m == eventmapnr) fprintf(th, "#define src_event src_ln%d\n", m); @@ -237,7 +300,27 @@ comwork(FILE *fd, Lextok *now, int m) case GT: Cat1(">"); break; case LT: Cat1("<"); break; case NE: Cat1("!="); break; - case EQ: Cat1("=="); break; + case EQ: + if (ltl_mode + && now->lft->ntyp == 'p' + && now->rgt->ntyp == 'q') /* remote ref */ + { Lextok *p = now->lft->lft; + + fprintf(fd, "("); + fprintf(fd, "%s", p->sym->name); + if (p->lft) + { fprintf(fd, "["); + putstmnt(fd, p->lft, 0); /* pid */ + fprintf(fd, "]"); + } + fprintf(fd, "@"); + fprintf(fd, "%s", now->rgt->sym->name); + fprintf(fd, ")"); + break; + } + Cat1("=="); + break; + case OR: Cat1("||"); break; case AND: Cat1("&&"); break; case LSHIFT: Cat1("<<"); break; @@ -298,6 +381,22 @@ comwork(FILE *fd, Lextok *now, int m) case ENABLED: Cat3("enabled(", now->lft, ")"); break; + case GET_P: if (old_priority_rules) + { fprintf(fd, "1"); + } else + { Cat3("get_priority(", now->lft, ")"); + } + break; + + case SET_P: if (!old_priority_rules) + { fprintf(fd, "set_priority("); + comwork(fd, now->lft->lft, m); + fprintf(fd, ", "); + comwork(fd, now->lft->rgt, m); + fprintf(fd, ")"); + } + break; + case EVAL: Cat3("eval(", now->lft, ")"); break; @@ -320,12 +419,14 @@ comwork(FILE *fd, Lextok *now, int m) } break; - case ASGN: comwork(fd,now->lft,m); + case ASGN: + if (check_track(now) == STRUCT) { break; } + comwork(fd,now->lft,m); fprintf(fd," = "); comwork(fd,now->rgt,m); break; - case PRINT: { char c, buf[512]; + case PRINT: { char c, buf[1024]; strncpy(buf, now->sym->name, 510); for (i = j = 0; i < 510; i++, j++) { c = now->sym->name[i]; @@ -349,9 +450,23 @@ comwork(FILE *fd, Lextok *now, int m) comwork(fd, now->lft, m); fprintf(fd, ")"); break; - case NAME: putname(fd, "", now, m, ""); + case NAME: + putname(fd, "", now, m, ""); break; - case 'p': putremote(fd, now, m); + + case 'p': + if (ltl_mode) + { fprintf(fd, "%s", now->lft->sym->name); /* proctype */ + if (now->lft->lft) + { fprintf(fd, "["); + putstmnt(fd, now->lft->lft, 0); /* pid */ + fprintf(fd, "]"); + } + fprintf(fd, ":"); /* remote varref */ + fprintf(fd, "%s", now->sym->name); /* varname */ + break; + } + putremote(fd, now, m); break; case 'q': fprintf(fd, "%s", now->sym->name); break; @@ -366,7 +481,7 @@ comwork(FILE *fd, Lextok *now, int m) case ELSE: fprintf(fd, "else"); break; case '@': fprintf(fd, "-end-"); break; - case D_STEP: fprintf(fd, "D_STEP"); break; + case D_STEP: fprintf(fd, "D_STEP%d", now->ln); break; case ATOMIC: fprintf(fd, "ATOMIC"); break; case NON_ATOMIC: fprintf(fd, "sub-sequence"); break; case IF: fprintf(fd, "IF"); break; diff --git a/sys/src/cmd/spin/pangen3.h b/sys/src/cmd/spin/pangen3.h index 931a598f5..59c1ed146 100644 --- a/sys/src/cmd/spin/pangen3.h +++ b/sys/src/cmd/spin/pangen3.h @@ -1,22 +1,19 @@ /***** spin: pangen3.h *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ -static char *Head0[] = { +static const char *Head0[] = { "#if defined(BFS) && defined(REACH)", - "#undef REACH", /* redundant with bfs */ + " #undef REACH", /* redundant with bfs */ "#endif", "#ifdef VERI", - "#define BASE 1", + " #define BASE 1", "#else", - "#define BASE 0", + " #define BASE 0", "#endif", "typedef struct Trans {", " short atom; /* if &2 = atomic trans; if &8 local */", @@ -37,108 +34,131 @@ static char *Head0[] = { " int back; /* index return transition */", " struct Trans *nxt;", "} Trans;\n", - "#define qptr(x) (((uchar *)&now)+(int)q_offset[x])", - "#define pptr(x) (((uchar *)&now)+(int)proc_offset[x])", -/* "#define Pptr(x) ((proc_offset[x])?pptr(x):noptr)", */ - "extern uchar *Pptr(int);", - "#define q_sz(x) (((Q0 *)qptr(x))->Qlen)\n", - "#ifndef VECTORSZ", - "#define VECTORSZ 1024 /* sv size in bytes */", + "#ifdef TRIX", + " #define qptr(x) (channels[x]->body)", + " #define pptr(x) (processes[x]->body)", + "#else", + " #define qptr(x) (((uchar *)&now)+(int)q_offset[x])", + " #define pptr(x) (((uchar *)&now)+(int)proc_offset[x])", +/* " #define Pptr(x) ((proc_offset[x])?pptr(x):noptr)", */ + "#endif", + "extern uchar *Pptr(int);", + "extern uchar *Qptr(int);", + + "#define q_sz(x) (((Q0 *)qptr(x))->Qlen)", + "", + "#ifdef TRIX", + " #ifdef VECTORSZ", + " #undef VECTORSZ", /* backward compatibility */ + " #endif", + " #if WS==4", + " #define VECTORSZ 2056 /* ((MAXPROC+MAXQ+4)*sizeof(uchar *)) */", + " #else", + " #define VECTORSZ 4112 /* the formula causes probs in preprocessing */", + " #endif", + "#else", + " #ifndef VECTORSZ", + " #define VECTORSZ 1024 /* sv size in bytes */", + " #endif", "#endif\n", + "#define MAXQ 255", + "#define MAXPROC 255", + "", 0, }; -static char *Header[] = { +static const char *Header[] = { "#ifdef VERBOSE", - "#ifndef CHECK", - "#define CHECK", - "#endif", - "#ifndef DEBUG", - "#define DEBUG", - "#endif", + " #ifndef CHECK", + " #define CHECK", + " #endif", + " #ifndef DEBUG", + " #define DEBUG", + " #endif", "#endif", "#ifdef SAFETY", - "#ifndef NOFAIR", - "#define NOFAIR", - "#endif", + " #ifndef NOFAIR", + " #define NOFAIR", + " #endif", "#endif", +#if 0 + NOREDUCE BITSTATE SAFETY MA WS>4 + CNTRSTACK: - + + d - + FULLSTACK: + d - - d + - + d d d + - + + d + + - - d d d + Neither: + d + d d + + d d + d +#endif "#ifdef NOREDUCE", - "#ifndef XUSAFE", - "#define XUSAFE", - "#endif", - "#if !defined(SAFETY) && !defined(MA)", - "#define FULLSTACK", - "#endif", + " #ifndef XUSAFE", + " #define XUSAFE", + " #endif", + " #if !defined(SAFETY) && !defined(MA)", + " #define FULLSTACK", /* => NOREDUCE && !SAFETY && !MA */ + " #endif", "#else", - "#ifdef BITSTATE", - "#ifdef SAFETY && !defined(HASH64)", - "#define CNTRSTACK", - "#else", - "#define FULLSTACK", - "#endif", - "#else", - "#define FULLSTACK", - "#endif", + " #ifdef BITSTATE", + " #if defined(SAFETY) && WS<=4", + " #define CNTRSTACK", /* => !NOREDUCE && BITSTATE && SAFETY && WS<=4 */ + " #else", + " #define FULLSTACK", /* => !NOREDUCE && BITSTATE && (!SAFETY || WS>4) */ + " #endif", + " #else", + " #define FULLSTACK", /* => !NOREDUCE && !BITSTATE */ + " #endif", "#endif", "#ifdef BITSTATE", - "#ifndef NOCOMP", - "#define NOCOMP", - "#endif", - "#if !defined(LC) && defined(SC)", - "#define LC", - "#endif", + " #ifndef NOCOMP", + " #define NOCOMP", + " #endif", + " #if !defined(LC) && defined(SC)", + " #define LC", + " #endif", "#endif", "#if defined(COLLAPSE2) || defined(COLLAPSE3) || defined(COLLAPSE4)", - "/* accept the above for backward compatibility */", - "#define COLLAPSE", + " /* accept the above for backward compatibility */", + " #define COLLAPSE", "#endif", "#ifdef HC", - "#undef HC", - "#define HC4", + " #undef HC", + " #define HC4", "#endif", - "#ifdef HC0", /* 32 bits */ - "#define HC 0", - "#endif", - "#ifdef HC1", /* 32+8 bits */ - "#define HC 1", - "#endif", - "#ifdef HC2", /* 32+16 bits */ - "#define HC 2", - "#endif", - "#ifdef HC3", /* 32+24 bits */ - "#define HC 3", - "#endif", - "#ifdef HC4", /* 32+32 bits - combine with -DMA=8 */ - "#define HC 4", - "#endif", - "#ifdef COLLAPSE", - "unsigned long ncomps[256+2];", - "#endif", - - "#define MAXQ 255", - "#define MAXPROC 255", - "#define WS sizeof(long) /* word size in bytes */", - "typedef struct Stack { /* for queues and processes */", + "#if defined(HC0) || defined(HC1) || defined(HC2) || defined(HC3) || defined(HC4)", + " #define HC 4", /* 2x32 bits */ + "#endif", /* really only one hashcompact mode, not 5 */ + "", + "typedef struct _Stack { /* for queues and processes */", "#if VECTORSZ>32000", " int o_delta;", - " int o_offset;", - " int o_skip;", + " #ifndef TRIX", + " int o_offset;", + " int o_skip;", + " #endif", " int o_delqs;", "#else", " short o_delta;", - " short o_offset;", - " short o_skip;", + " #ifndef TRIX", + " short o_offset;", + " short o_skip;", + " #endif", " short o_delqs;", "#endif", " short o_boq;", + "#ifdef TRIX", + " short parent;", + " char *b_ptr;", /* used in delq/q_restor and delproc/p_restor */ + "#else", + " char *body;", /* full copy of state vector in non-trix mode */ + "#endif", "#ifndef XUSAFE", " char *o_name;", "#endif", - " char *body;", - " struct Stack *nxt;", - " struct Stack *lst;", - "} Stack;\n", + " struct _Stack *nxt;", + " struct _Stack *lst;", + "} _Stack;\n", "typedef struct Svtack { /* for complete state vector */", "#if VECTORSZ>32000", " int o_delta;", @@ -153,35 +173,15 @@ static char *Header[] = { 0, }; -static char *Header0[] = { +static const char *Header0[] = { " char *body;", " struct Svtack *nxt;", " struct Svtack *lst;", "} Svtack;\n", - "Trans ***trans; /* 1 ptr per state per proctype */\n", - "#if defined(FULLSTACK) || defined(BFS)", - "struct H_el *Lstate;", - "#endif", - "int depthfound = -1; /* loop detection */", - "#if VECTORSZ>32000", - "int proc_offset[MAXPROC];", - "int q_offset[MAXQ];", - "#else", - "short proc_offset[MAXPROC];", - "short q_offset[MAXQ];", - "#endif", - "uchar proc_skip[MAXPROC];", - "uchar q_skip[MAXQ];", - "unsigned long vsize; /* vector size in bytes */", - "#ifdef SVDUMP", - "int vprefix=0, svfd; /* runtime option -pN */", - "#endif", - "char *tprefix = \"trail\"; /* runtime option -tsuffix */", - "short boq = -1; /* blocked_on_queue status */", 0, }; -static char *Head1[] = { +static const char *Head1[] = { "typedef struct State {", " uchar _nr_pr;", " uchar _nr_qs;", @@ -207,24 +207,32 @@ static char *Head1[] = { #endif " unsigned short _vsz;", "#else", - " unsigned long _vsz;", + " ulong _vsz;", "#endif", "#endif", - "#ifdef HAS_LAST", /* cannot go before _cnt - see hstore() */ + "#ifdef HAS_LAST", /* cannot go before _cnt - see h_store() */ " uchar _last; /* pid executed in last step */", "#endif", + + "#if defined(BITSTATE) && defined(BCS) && defined(STORE_CTX)", + " uchar _ctx; /* nr of context switches so far */", + "#endif", + "#if defined(BFS_PAR) && defined(L_BOUND)", + " uchar _l_bnd; /* bounded liveness */", + " uchar *_l_sds; /* seed state */", + "#endif", "#ifdef EVENT_TRACE", - "#if nstates_event<256", - " uchar _event;", - "#else", - " unsigned short _event;", - "#endif", + " #if nstates_event<256", + " uchar _event;", + " #else", + " unsigned short _event;", + " #endif", "#endif", 0, }; -static char *Addp0[] = { +static const char *Addp0[] = { /* addproc(....parlist... */ ")", "{ int j, h = now._nr_pr;", "#ifndef NOCOMP", @@ -235,45 +243,66 @@ static char *Addp0[] = { " if (TstOnly) return (h < MAXPROC);", "#endif", "#ifndef NOBOUNDCHECK", - "/* redefine Index only within this procedure */", - "#undef Index", - "#define Index(x, y) Boundcheck(x, y, 0, 0, 0)", + " /* redefine Index only within this procedure */", + " #undef Index", + " #define Index(x, y) Boundcheck(x, y, 0, 0, 0)", "#endif", " if (h >= MAXPROC)", " Uerror(\"too many processes\");", + "#ifdef V_TRIX", + " printf(\"%%4d: add process %%d\\n\", depth, h);", + "#endif", " switch (n) {", " case 0: j = sizeof(P0); break;", 0, }; -static char *Addp1[] = { +static const char *Addp1[] = { " default: Uerror(\"bad proc - addproc\");", " }", + " #ifdef BFS_PAR", + " bfs_prepmask(1); /* addproc */", + " #endif", + + "#ifdef TRIX", + " vsize += sizeof(H_el *);", + "#else", " if (vsize%%WS)", " proc_skip[h] = WS-(vsize%%WS);", " else", " proc_skip[h] = 0;", - "#ifndef NOCOMP", - " for (k = vsize + (int) proc_skip[h]; k > vsize; k--)", - " Mask[k-1] = 1; /* align */", - "#endif", + " #if !defined(NOCOMP) && !defined(HC)", + " for (k = vsize + (int) proc_skip[h]; k > vsize; k--)", + " Mask[k-1] = 1; /* align */", + " #endif", " vsize += (int) proc_skip[h];", " proc_offset[h] = vsize;", - "#ifdef SVDUMP", + " vsize += j;", + " #if defined(SVDUMP) && defined(VERBOSE)", " if (vprefix > 0)", " { int dummy = 0;", " write(svfd, (uchar *) &dummy, sizeof(int)); /* mark */", " write(svfd, (uchar *) &h, sizeof(int));", " write(svfd, (uchar *) &n, sizeof(int));", - "#if VECTORSZ>32000", + " #if VECTORSZ>32000", " write(svfd, (uchar *) &proc_offset[h], sizeof(int));", - "#else", - " write(svfd, (uchar *) &proc_offset[h], sizeof(short));", - "#endif", " write(svfd, (uchar *) &now, vprefix-4*sizeof(int)); /* padd */", + " #else", + " write(svfd, (uchar *) &proc_offset[h], sizeof(short));", + " write(svfd, (uchar *) &now, vprefix-3*sizeof(int)-sizeof(short)); /* padd */", + " #endif", + " }", + " #endif", + "#endif", + + " now._nr_pr += 1;", + "#if defined(BCS) && defined(CONSERVATIVE)", + " if (now._nr_pr >= CONSERVATIVE*8)", + " { printf(\"pan: error: too many processes -- recompile with \");", + " printf(\"-DCONSERVATIVE=%%d\\n\", CONSERVATIVE+1);", + " pan_exit(1);", " }", "#endif", - " now._nr_pr += 1;", " if (fairness && ((int) now._nr_pr + 1 >= (8*NFAIR)/2))", " { printf(\"pan: error: too many processes -- current\");", " printf(\" max is %%d procs (-DNFAIR=%%d)\\n\",", @@ -282,78 +311,134 @@ static char *Addp1[] = { " NFAIR+1);", " pan_exit(1);", " }", - - " vsize += j;", "#ifndef NOVSZ", " now._vsz = vsize;", "#endif", - "#ifndef NOCOMP", - " for (k = 1; k <= Air[n]; k++)", - " Mask[vsize - k] = 1; /* pad */", - " Mask[vsize-j] = 1; /* _pid */", - "#endif", " hmax = max(hmax, vsize);", + + "#ifdef TRIX", + " #ifndef BFS", + " if (freebodies)", + " { processes[h] = freebodies;", + " freebodies = freebodies->nxt;", + " } else", + " { processes[h] = (TRIX_v6 *) emalloc(sizeof(TRIX_v6));", + " processes[h]->body = (uchar *) emalloc(Maxbody * sizeof(char));", + " }", + " processes[h]->modified = 1; /* addproc */", + " #endif", + " processes[h]->psize = j;", + " processes[h]->parent_pid = calling_pid;", + " processes[h]->nxt = (TRIX_v6 *) 0;", + "#else", + " #if !defined(NOCOMP) && !defined(HC)", + " for (k = 1; k <= Air[n]; k++)", + " Mask[vsize - k] = 1; /* pad */", + " Mask[vsize-j] = 1; /* _pid */", + " #endif", + " #ifdef BFS_PAR", + " bfs_fixmask(1); /* addproc */", + " #endif", " if (vsize >= VECTORSZ)", " { printf(\"pan: error, VECTORSZ too small, recompile pan.c\");", - " printf(\" with -DVECTORSZ=N with N>%%d\\n\", vsize);", + " printf(\" with -DVECTORSZ=N with N>%%d\\n\", (int) vsize);", " Uerror(\"aborting\");", " }", + "#endif", + " memset((char *)pptr(h), 0, j);", " this = pptr(h);", " if (BASE > 0 && h > 0)", - " ((P0 *)this)->_pid = h-BASE;", - " else", - " ((P0 *)this)->_pid = h;", + " { ((P0 *)this)->_pid = h-BASE;", + " } else", + " { ((P0 *)this)->_pid = h;", + " }", " switch (n) {", 0, }; -static char *Addq0[] = { +static const char *Addq0[] = { + "", "int", - "addqueue(int n, int is_rv)", + "addqueue(int calling_pid, int n, int is_rv)", "{ int j=0, i = now._nr_qs;", - "#ifndef NOCOMP", + "#if !defined(NOCOMP) && !defined(TRIX)", " int k;", "#endif", " if (i >= MAXQ)", " Uerror(\"too many queues\");", + "#ifdef V_TRIX", + " printf(\"%%4d: add queue %%d\\n\", depth, i);", + "#endif", " switch (n) {", 0, }; -static char *Addq1[] = { +static const char *Addq1[] = { " default: Uerror(\"bad queue - addqueue\");", " }", + " #ifdef BFS_PAR", + " bfs_prepmask(2); /* addqueue */", + " #endif", + + "#ifdef TRIX", + " vsize += sizeof(H_el *);", + "#else", " if (vsize%%WS)", " q_skip[i] = WS-(vsize%%WS);", " else", " q_skip[i] = 0;", - "#ifndef NOCOMP", - " k = vsize;", - "#ifndef BFS", - " if (is_rv) k += j;", - "#endif", - " for (k += (int) q_skip[i]; k > vsize; k--)", - " Mask[k-1] = 1;", - "#endif", + " #if !defined(NOCOMP) && !defined(HC)", + " k = vsize;", + " #ifndef BFS", + " if (is_rv) k += j;", + " #endif", + " for (k += (int) q_skip[i]; k > vsize; k--)", + " Mask[k-1] = 1;", + " #endif", " vsize += (int) q_skip[i];", " q_offset[i] = vsize;", - " now._nr_qs += 1;", " vsize += j;", + " #ifdef BFS_PAR", + " bfs_fixmask(2); /* addqueue */", + " #endif", + "#endif", + + " now._nr_qs += 1;", "#ifndef NOVSZ", " now._vsz = vsize;", "#endif", " hmax = max(hmax, vsize);", + + "#ifdef TRIX", + " #ifndef BFS", + " if (freebodies)", + " { channels[i] = freebodies;", + " freebodies = freebodies->nxt;", + " } else", + " { channels[i] = (TRIX_v6 *) emalloc(sizeof(TRIX_v6));", + " channels[i]->body = (uchar *) emalloc(Maxbody * sizeof(char));", + " }", + " channels[i]->modified = 1; /* addq */", + " #endif", + " channels[i]->psize = j;", + " channels[i]->parent_pid = calling_pid;", + " channels[i]->nxt = (TRIX_v6 *) 0;", + "#else", " if (vsize >= VECTORSZ)", " Uerror(\"VECTORSZ is too small, edit pan.h\");", - " memset((char *)qptr(i), 0, j);", + "#endif", + + " if (j > 0)", /* zero if there are no queues */ + " { memset((char *)qptr(i), 0, j);", + " }", " ((Q0 *)qptr(i))->_t = n;", " return i+1;", "}\n", 0, }; -static char *Addq11[] = { +static const char *Addq11[] = { "{ int j; uchar *z;\n", "#ifdef HAS_SORTED", " int k;", @@ -362,13 +447,26 @@ static char *Addq11[] = { " uerror(\"ref to uninitialized chan name (sending)\");", " if (into >= (int) now._nr_qs || into < 0)", " Uerror(\"qsend bad queue#\");", + "#if defined(TRIX) && !defined(BFS)", + " #ifndef TRIX_ORIG", + " (trpt+1)->q_bup = now._ids_[now._nr_pr+into];", + " #ifdef V_TRIX", + " printf(\"%%4d: channel %%d s save %%p from %%d\\n\",", + " depth, into, (trpt+1)->q_bup, now._nr_pr+into);", + " #endif", + " #endif", + " channels[into]->modified = 1; /* qsend */", + " #ifdef V_TRIX", + " printf(\"%%4d: channel %%d modified\\n\", depth, into);", + " #endif", + "#endif", " z = qptr(into);", " j = ((Q0 *)qptr(into))->Qlen;", " switch (((Q0 *)qptr(into))->_t) {", 0, }; -static char *Addq2[] = { +static const char *Addq2[] = { " case 0: printf(\"queue %%d was deleted\\n\", into+1);", " default: Uerror(\"bad queue - qsend\");", " }", @@ -389,7 +487,7 @@ static char *Addq2[] = { 0, }; -static char *Addq3[] = { +static const char *Addq3[] = { " case 0: printf(\"queue %%d was deleted\\n\", from+1);", " }", " Uerror(\"bad queue q-zero\");", @@ -449,7 +547,11 @@ static char *Addq3[] = { "short q_recver[MAXQ+1];", "int", "q_R_check(int x, int who)", - "{ if (!q_recver[x])", + "{", + "#ifdef VERBOSE", + " printf(\"q_R_check x=%%d who=%%d\\n\", x, who);", + "#endif", + " if (!q_recver[x])", " { q_recver[x] = who+1;", "#if SYNC", " if (q_zero(x))", @@ -489,7 +591,7 @@ static char *Addq3[] = { 0, }; -static char *Addq4[] = { +static const char *Addq4[] = { " case 0: printf(\"queue %%d was deleted\\n\", from+1);", " }", " Uerror(\"bad queue - q_full\");", @@ -509,6 +611,19 @@ static char *Addq4[] = { " int j, k, r=0;\n", " if (!from--)", " uerror(\"ref to uninitialized chan name (receiving)\");", + "#if defined(TRIX) && !defined(BFS)", + " #ifndef TRIX_ORIG", + " (trpt+1)->q_bup = now._ids_[now._nr_pr+from];", + " #ifdef V_TRIX", + " printf(\"%%4d: channel %%d r save %%p from %%d\\n\",", + " depth, from, (trpt+1)->q_bup, now._nr_pr+from);", + " #endif", + " #endif", + " channels[from]->modified = 1; /* qrecv */", + " #ifdef V_TRIX", + " printf(\"%%4d: channel %%d modified\\n\", depth, from);", + " #endif", + "#endif", " if (from >= (int) now._nr_qs || from < 0)", " Uerror(\"qrecv bad queue#\");", " z = qptr(from);", @@ -520,7 +635,7 @@ static char *Addq4[] = { 0, }; -static char *Addq5[] = { +static const char *Addq5[] = { " case 0: printf(\"queue %%d was deleted\\n\", from+1);", " default: Uerror(\"bad queue - qrecv\");", " }", @@ -528,7 +643,7 @@ static char *Addq5[] = { "}", "#endif\n", "#ifndef BITSTATE", - "#ifdef COLLAPSE", + " #ifdef COLLAPSE", "long", "col_q(int i, char *z)", "{ int j=0, k;", @@ -538,15 +653,22 @@ static char *Addq5[] = { 0, }; -static char *Code0[] = { +static const char *Code0[] = { "void", "run(void)", "{ /* int i; */", " memset((char *)&now, 0, sizeof(State));", - " vsize = (unsigned long) (sizeof(State) - VECTORSZ);", + " vsize = (ulong) (sizeof(State) - VECTORSZ);", "#ifndef NOVSZ", " now._vsz = vsize;", "#endif", + "#ifdef TRIX", + " if (VECTORSZ != sizeof(now._ids_))", + " { printf(\"VECTORSZ is %%d, but should be %%d in this mode\\n\",", + " VECTORSZ, (int) sizeof(now._ids_));", + " Uerror(\"VECTORSZ set incorrectly, recompile Spin (not pan.c)\");", + " }", + "#endif", "/* optional provisioning statements, e.g. to */", "/* set hidden variables, used as constants */", "#ifdef PROV", @@ -556,151 +678,311 @@ static char *Code0[] = { 0, }; -static char *R0[] = { - " Maxbody = max(Maxbody, sizeof(P%d));", +static const char *R0[] = { + " Maxbody = max(Maxbody, ((int) sizeof(P%d)));", " reached[%d] = reached%d;", - " accpstate[%d] = (uchar *) emalloc(nstates%d);", - " 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;", + " accpstate[%d] = (uchar *) emalloc(_nstates%d);", + " progstate[%d] = (uchar *) emalloc(_nstates%d);", + " loopstate%d = loopstate[%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));", + " stopstate[%d][_endstate%d] = 1;", 0, }; -static char *R0a[] = { - " retrans(%d, nstates%d, start%d, src_ln%d, reached%d);", - 0, -}; -static char *R0b[] = { - " if (state_tables)", - " { printf(\"\\nTransition Type: \");", - " printf(\"A=atomic; D=d_step; L=local; G=global\\n\");", - " printf(\"Source-State Labels: \");", - " printf(\"p=progress; e=end; a=accept;\\n\");", - "#ifdef MERGED", - " printf(\"Note: statement merging was used. Only the first\\n\");", - " printf(\" stmnt executed in each merge sequence is shown\\n\");", - " printf(\" (use spin -a -o3 to disable statement merging)\\n\");", - "#endif", - " pan_exit(0);", - " }", +static const char *R00[] = { + " NrStates[%d] = _nstates%d;", 0, }; -static char *Code1[] = { +static const char *R0a[] = { + " retrans(%d, _nstates%d, _start%d, src_ln%d, reached%d, loopstate%d);", + 0, +}; + +static const char *Code1[] = { "#ifdef NP", - "#define ACCEPT_LAB 1 /* at least 1 in np_ */", + " #define ACCEPT_LAB 1 /* at least 1 in np_ */", "#else", - "#define ACCEPT_LAB %d /* user-defined accept labels */", + " #define ACCEPT_LAB %d /* user-defined accept labels */", + "#endif", + "#ifdef MEMCNT", + " #ifdef MEMLIM", + " #warning -DMEMLIM takes precedence over -DMEMCNT", + " #undef MEMCNT", + " #else", + " #if MEMCNT<20", + " #warning using minimal value -DMEMCNT=20 (=1MB)", + " #define MEMLIM (1)", + " #undef MEMCNT", + " #else", + " #if MEMCNT==20", + " #define MEMLIM (1)", + " #undef MEMCNT", + " #else", + " #if MEMCNT>=50", + " #error excessive value for MEMCNT", + " #else", + " #define MEMLIM (1<<(MEMCNT-20))", + " #endif", + " #endif", + " #endif", + " #endif", + "#endif", + + "#if NCORE>1 && !defined(MEMLIM)", + " #define MEMLIM (2048) /* need a default, using 2 GB */", "#endif", 0, }; -static char *Code3[] = { +static const char *Code3[] = { "#define PROG_LAB %d /* progress labels */", 0, }; -static char *R2[] = { +static const char *R2[] = { "uchar *accpstate[%d];", "uchar *progstate[%d];", + "uchar *loopstate[%d];", "uchar *reached[%d];", "uchar *stopstate[%d];", "uchar *visstate[%d];", "short *mapstate[%d];", "#ifdef HAS_CODE", - "int NrStates[%d];", + " int NrStates[%d];", "#endif", 0, }; -static char *R3[] = { - " Maxbody = max(Maxbody, sizeof(Q%d));", +static const char *R3[] = { + " Maxbody = max(Maxbody, ((int) sizeof(Q%d)));", 0, }; -static char *R4[] = { - " r_ck(reached%d, nstates%d, %d, src_ln%d, src_file%d);", +static const char *R4[] = { + " r_ck(reached%d, _nstates%d, %d, src_ln%d, src_file%d);", 0, }; -static char *R5[] = { +static const char *R5[] = { " case %d: j = sizeof(P%d); break;", 0, }; -static char *R6[] = { +static const char *R6[] = { " }", " this = o_this;", + "#ifdef TRIX", + " re_mark_all(1); /* addproc */", + "#endif", " return h-BASE;", "#ifndef NOBOUNDCHECK", - "#undef Index", - "#define Index(x, y) Boundcheck(x, y, II, tt, t)", + " #undef Index", + " #define Index(x, y) Boundcheck(x, y, II, tt, t)", "#endif", "}\n", "#if defined(BITSTATE) && defined(COLLAPSE)", - "/* just to allow compilation, to generate the error */", - "long col_p(int i, char *z) { return 0; }", - "long col_q(int i, char *z) { return 0; }", + " /* just to allow compilation, to generate the error */", + " long col_p(int i, char *z) { return 0; }", + " long col_q(int i, char *z) { return 0; }", "#endif", "#ifndef BITSTATE", - "#ifdef COLLAPSE", + " #ifdef COLLAPSE", "long", "col_p(int i, char *z)", - "{ int j, k; unsigned long ordinal(char *, long, short);", + "{ int j, k; ulong ordinal(char *, long, short);", " char *x, *y;", " P0 *ptr = (P0 *) pptr(i);", " switch (ptr->_t) {", " case 0: j = sizeof(P0); break;", 0, }; -static char *R8a[] = { +static const char *R7a[] = { + "void\nre_mark_all(int whichway)", + "{ int j;", + " #ifdef V_TRIX", + " printf(\"%%d: re_mark_all channels %%d\\n\", depth, whichway);", + " #endif", + " #ifndef BFS", + " for (j = 0; j < now._nr_qs; j++)", + " channels[j]->modified = 1; /* channel index moved */", + " #endif", + " #ifndef TRIX_ORIG", + " if (whichway > 0)", + " { for (j = now._nr_pr + now._nr_qs - 1; j >= now._nr_pr; j--)", + " now._ids_[j] = now._ids_[j-1];", + " } else", + " { for (j = now._nr_pr; j < now._nr_pr + now._nr_qs; j++)", + " now._ids_[j] = now._ids_[j+1];", + " }", + " #endif", + "}", + 0, +}; + +static const char *R7b[] = { + "#ifdef BFS_PAR", + "inline void", + "bfs_prepmask(int caller)", + "{", + "#if !defined(NOCOMP) && !defined(HC)", + " memcpy((char *) &tmp_msk, (const char *) Mask, sizeof(State));", + " Mask = (uchar *) &tmp_msk;", + "#endif", + " switch (caller) {", + " case 1: /* addproc */", + "#if VECTORSZ>32000", + " memcpy((char *) P_o_tmp, (const char *) proc_offset, MAXPROC*sizeof(int));", + "#else", + " memcpy((char *) P_o_tmp, (const char *) proc_offset, MAXPROC*sizeof(short));", + "#endif", + " memcpy((char *) P_s_tmp, (const char *) proc_skip, MAXPROC*sizeof(uchar));", + " proc_offset = P_o_tmp;", + " proc_skip = (uchar *) &P_s_tmp[0];", + " break;", + " case 2: /* addqueue */", + "#if VECTORSZ>32000", + " memcpy((char *) Q_o_tmp, (const char *) q_offset, MAXQ*sizeof(int));", + "#else", + " memcpy((char *) Q_o_tmp, (const char *) q_offset, MAXQ*sizeof(short));", + "#endif", + " memcpy((char *) Q_s_tmp, (const char *) q_skip, MAXQ*sizeof(uchar));", + " q_offset = Q_o_tmp;", + " q_skip = (uchar *) &Q_s_tmp[0];", + " break;", + " case 3: /* no nothing */", + " break;", + " default: /* cannot happen */", + " Uerror(\"no good\");", + " break;", + " }", + "}", + "", + "typedef struct BFS_saves BFS_saves;", + "struct BFS_saves {", + " char *m;", + " BFS_saves *nxt;", + "} *bfs_save_po,", + " *bfs_save_ps,", + "#if !defined(NOCOMP) && !defined(HC)", + " *bfs_save_mask,", + "#endif", + " *bfs_save_qo,", + " *bfs_save_qs;", + "", + "extern volatile uchar *sh_malloc(ulong);", + "static int bfs_runs; /* 0 before local heaps are initialized */", + "", + "void", + "bfs_swoosh(BFS_saves **where, char **what, int howmuch)", + "{ BFS_saves *m;", + " for (m = *where; m; m = m->nxt)", + " { if (memcmp(m->m, *what, howmuch) == 0)", + " { *what = m->m;", + " return;", + " } }", + " m = (BFS_saves *) emalloc(sizeof(BFS_saves));", + " if (bfs_runs)", + " { m->m = (char *) sh_malloc(howmuch);", + " } else", + " { m->m = (char *) sh_pre_malloc(howmuch);", + " }", + " memcpy(m->m, *what, howmuch);", + " m->nxt = *where;", + " *where = m;", + " *what = m->m;", + "}", + "", + "void", + "bfs_fixmask(int caller)", /* 1=addproc, 2=addqueue */ + "{", + "#if !defined(NOCOMP) && !defined(HC)", + " bfs_swoosh(&bfs_save_mask, (char **) &Mask, sizeof(State));", + "#endif", + "#ifndef TRIX", + " switch (caller) {", + " case 1: /* addproc */", + " #if VECTORSZ>32000", + " bfs_swoosh(&bfs_save_po, (char **) &proc_offset, MAXPROC*sizeof(int));", + " #else", + " bfs_swoosh(&bfs_save_po, (char **) &proc_offset, MAXPROC*sizeof(short));", + " #endif", + " bfs_swoosh(&bfs_save_ps, (char **) &proc_skip, MAXPROC*sizeof(uchar));", + " break;", + " case 2: /* addqueue */", + " #if VECTORSZ>32000", + " bfs_swoosh(&bfs_save_qo, (char **) &q_offset, MAXQ*sizeof(int));", + " #else", + " bfs_swoosh(&bfs_save_qo, (char **) &q_offset, MAXQ*sizeof(short));", + " #endif", + " bfs_swoosh(&bfs_save_qs, (char **) &q_skip, MAXQ*sizeof(uchar));", + " break;", + " case 3: /* do nothing */", + " break;", + " default:", + " Uerror(\"double plus ungood\");", + " break;", + " }", + "#endif", + "}", + "#endif", + 0, +}; +static const char *R8a[] = { " default: Uerror(\"bad proctype - collapse\");", " }", " if (z) x = z; else x = scratch;", " y = (char *) ptr; k = proc_offset[i];", - + "", + "#if !defined(NOCOMP) && !defined(HC)", " for ( ; j > 0; j--, y++)", " if (!Mask[k++]) *x++ = *y;", - + "#else", + " memcpy(x, y, j);", + " x += j;", + "#endif", " for (j = 0; j < WS-1; j++)", " *x++ = 0;", " x -= j;", " if (z) return (long) (x - z);", " return ordinal(scratch, x-scratch, (short) (2+ptr->_t));", "}", - "#endif", + " #endif", "#endif", 0, }; -static char *R8b[] = { +static const char *R8b[] = { " default: Uerror(\"bad qtype - collapse\");", " }", " if (z) x = z; else x = scratch;", " y = (char *) ptr; k = q_offset[i];", + "#if NQS > 0", " /* no need to store the empty slots at the end */", " j -= (q_max[ptr->_t] - ptr->Qlen) * ((j - 2)/q_max[ptr->_t]);", - + "#endif", + "", + "#if !defined(NOCOMP) && !defined(HC)", " for ( ; j > 0; j--, y++)", " if (!Mask[k++]) *x++ = *y;", - + "#else", + " memcpy(x, y, j);", + " x += j;", + "#endif", " 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", "#endif", 0, }; -static char *R12[] = { +static const char *R12[] = { "\t\tcase %d: r = ((Q%d *)z)->contents[slot].fld%d; break;", 0, }; -char *R13[] = { +const char *R13[] = { "int ", "unsend(int into)", "{ int _m=0, j; uchar *z;\n", @@ -709,13 +991,27 @@ char *R13[] = { "#endif", " if (!into--)", " uerror(\"ref to uninitialized chan (unsend)\");", + "#if defined(TRIX) && !defined(BFS)", + " #ifndef TRIX_ORIG", + " now._ids_[now._nr_pr+into] = trpt->q_bup;", + " #ifdef V_TRIX", + " printf(\"%%4d: channel %%d s restore %%p into %%d\\n\",", + " depth, into, trpt->q_bup, now._nr_pr+into);", + " #endif", + " #else", + " channels[into]->modified = 1; /* unsend */", + " #ifdef V_TRIX", + " printf(\"%%4d: channel %%d unmodify\\n\", depth, into);", + " #endif", + " #endif", + "#endif", " z = qptr(into);", " j = ((Q0 *)z)->Qlen;", " ((Q0 *)z)->Qlen = --j;", " switch (((Q0 *)qptr(into))->_t) {", 0, }; -char *R14[] = { +const char *R14[] = { " default: Uerror(\"bad queue - unsend\");", " }", " return _m;", @@ -725,40 +1021,53 @@ char *R14[] = { "{ int j; uchar *z;\n", " if (!from--)", " uerror(\"ref to uninitialized chan (unrecv)\");", + "#if defined(TRIX) && !defined(BFS)", + " #ifndef TRIX_ORIG", + " now._ids_[now._nr_pr+from] = trpt->q_bup;", + " #ifdef V_TRIX", + " printf(\"%%4d: channel %%d r restore %%p into %%d\\n\",", + " depth, from, trpt->q_bup, now._nr_pr+from);", + " #endif", + " #else", + " channels[from]->modified = 1; /* unrecv */", + " #ifdef V_TRIX", + " printf(\"%%4d: channel %%d unmodify\\n\", depth, from);", + " #endif", + " #endif", + "#endif", " z = qptr(from);", " j = ((Q0 *)z)->Qlen;", " if (strt) ((Q0 *)z)->Qlen = j+1;", " switch (((Q0 *)qptr(from))->_t) {", 0, }; -char *R15[] = { +const char *R15[] = { " default: Uerror(\"bad queue - qrecv\");", " }", "}", 0, }; -static char *Proto[] = { +static const char *Proto[] = { "", "/** function prototypes **/", - "char *emalloc(unsigned long);", - "char *Malloc(unsigned long);", + "char *emalloc(ulong);", + "char *Malloc(ulong);", "int Boundcheck(int, int, int, int, Trans *);", - "int addqueue(int, int);", + "int addqueue(int, int, int);", "/* int atoi(char *); */", "/* int abort(void); */", "int close(int);", /* should probably remove this */ #if 0 "#ifndef SC", - "int creat(char *, unsigned short);", - "int write(int, void *, unsigned);", + " int creat(char *, unsigned short);", + " int write(int, void *, unsigned);", "#endif", #endif "int delproc(int, int);", "int endstate(void);", - "int hstore(char *, int);", -"#ifdef MA", - "int gstore(char *, int, uchar);", -"#endif", + "int find_claim(char *);", + "int h_store(char *, int);", + "int pan_rand(void);", "int q_cond(short, Trans *);", "int q_full(int);", "int q_len(int);", @@ -766,65 +1075,353 @@ static char *Proto[] = { "int qrecv(int, int, int, int);", "int unsend(int);", "/* void *sbrk(int); */", - "void Uerror(char *);", - "void assert(int, char *, int, int, Trans *);", + "void spin_assert(int, char *, int, int, Trans *);", + "#ifdef BFS_PAR", + "void bfs_printf(const char *, ...);", + "volatile uchar *sh_pre_malloc(ulong);", + "#endif", "void c_chandump(int);", "void c_globals(void);", "void c_locals(int, int);", "void checkcycles(void);", "void crack(int, int, Trans *, short *);", + "void d_sfh(uchar *, int);", "void d_hash(uchar *, int);", + "void m_hash(uchar *, int);", "void s_hash(uchar *, int);", - "void r_hash(uchar *, int);", "void delq(int);", + "void dot_crack(int, int, Trans *);", "void do_reach(void);", "void pan_exit(int);", "void exit(int);", - "void hinit(void);", + "#ifdef BFS_PAR", + " void bfs_setup_mem(void);", + "#endif", + "#ifdef BITSTATE", + " void sinit(void);", + "#else", + " void hinit(void);", + "#endif", "void imed(Trans *, int, int, int);", "void new_state(void);", "void p_restor(int);", "void putpeg(int, int);", "void putrail(void);", "void q_restor(void);", - "void retrans(int, int, int, short *, uchar *);", + "void retrans(int, int, int, short *, uchar *, uchar *);", + "void select_claim(int);", "void settable(void);", "void setq_claim(int, int, char *, int, char *);", "void sv_restor(void);", "void sv_save(void);", "void tagtable(int, int, int, short *, uchar *);", - "void uerror(char *);", + "void do_dfs(int, int, int, short *, uchar *, uchar *);", "void unrecv(int, int, int, int, int);", "void usage(FILE *);", - "void wrap_stats(void);", + "void wrap_stats(void);\n", + "#ifdef MA", + " int g_store(char *, int, uchar);", + "#endif", "#if defined(FULLSTACK) && defined(BITSTATE)", - "int onstack_now(void);", - "void onstack_init(void);", - "void onstack_put(void);", - "void onstack_zap(void);", + " int onstack_now(void);", + " void onstack_init(void);", + " void onstack_put(void);", + " void onstack_zap(void);", "#endif", "#ifndef XUSAFE", - "int q_S_check(int, int);", - "int q_R_check(int, int);", - "uchar q_claim[MAXQ+1];", - "char *q_name[MAXQ+1];", - "char *p_name[MAXPROC+1];", + " int q_S_check(int, int);", + " int q_R_check(int, int);", + " uchar q_claim[MAXQ+1];", + " char *q_name[MAXQ+1];", + " char *p_name[MAXPROC+1];", "#endif", + "", + "#ifndef NO_V_PROVISO", + " #define V_PROVISO", + "#endif", + "#if !defined(NO_RESIZE) && !defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(SPACE) && !defined(USE_TDH) && NCORE==1", + " #define AUTO_RESIZE", + "#endif", + "", + "typedef struct Trail Trail;", + "typedef struct H_el H_el;", + "", + "struct H_el {", + " H_el *nxt;", + " #ifdef FULLSTACK", + " unsigned int tagged;", + " #if defined(BITSTATE) && !defined(NOREDUCE) && !defined(SAFETY)", + " unsigned int proviso;", /* uses just 1 bit 0/1 */ + " #endif", + " #endif", + " #if defined(CHECK) || (defined(COLLAPSE) && !defined(FULLSTACK))", + " ulong st_id;", + " #endif", + " #if !defined(SAFETY) || defined(REACH)", + " uint D;", + " #endif", + " #ifdef BCS", + " #ifndef CONSERVATIVE", + " #define CONSERVATIVE 1 /* good for up to 8 processes */", + " #endif", + " #ifdef CONSERVATIVE", + " #if CONSERVATIVE <= 0 || CONSERVATIVE>32", + " #error sensible values for CONSERVATIVE are 1..32 (256/8 = 32)", + " #endif", + " uchar ctx_pid[CONSERVATIVE];", /* pids setting lowest value */ + " #endif", + " uchar ctx_low;", /* lowest nr of context switches seen so far */ + " #endif", + " #if NCORE>1", + " /* could cost 1 extra word: 4 bytes if 32-bit and 8 bytes if 64-bit */", + " #ifdef V_PROVISO", + " uchar cpu_id; /* id of cpu that created the state */", + " #endif", + " #endif", + " #ifdef COLLAPSE", + " #if VECTORSZ<65536", + " ushort ln;", /* length of vector */ + " #else", + " ulong ln;", /* length of vector */ + " #endif", + " #endif", + " #if defined(AUTO_RESIZE) && !defined(BITSTATE)", + " ulong m_K1;", + " #endif", + " ulong state;", + "};", + "", + "#ifdef BFS_PAR", + "typedef struct BFS_Trail BFS_Trail;", + "struct BFS_Trail {", + " H_el *ostate;", + " int st;", + " int o_tt;", + " T_ID t_id;", /* could be uint, ushort, or uchar */ + " uchar pr;", + " uchar o_pm;", + " uchar tau;", + "};", + " #if SYNC>0", + " #undef BFS_NOTRAIL", /* just in case it was used */ + " #endif", + "#endif", + "", + "#ifdef RHASH", + " #ifndef PERMUTED", + " #define PERMUTED", + " #endif", + "#endif", + "", + "struct Trail {", + " int st; /* current state */", + " int o_tt;", + "#ifdef PERMUTED", + " uint seed;", + " uchar oII;", + "#endif", + " uchar pr; /* process id */", + " uchar tau; /* 8 bit-flags */", + " uchar o_pm; /* 8 more bit-flags */", + "", + " #if 0", + " Meaning of bit-flags on tau and o_pm:", + " tau&1 -> timeout enabled", + " tau&2 -> request to enable timeout 1 level up (in claim)", + " tau&4 -> current transition is a claim move", + " tau&8 -> current transition is an atomic move", + " tau&16 -> last move was truncated on stack", + " tau&32 -> current transition is a preselected move", + " tau&64 -> at least one next state is not on the stack", + " tau&128 -> current transition is a stutter move", + + " o_pm&1 -> the current pid moved -- implements else", + " o_pm&2 -> this is an acceptance state", + " o_pm&4 -> this is a progress state", + " o_pm&8 -> fairness alg rule 1 undo mark", + " o_pm&16 -> fairness alg rule 3 undo mark", + " o_pm&32 -> fairness alg rule 2 undo mark", + " o_pm&64 -> the current proc applied rule2", + " o_pm&128 -> a fairness, dummy move - all procs blocked", + " #endif", + "", + " #ifdef NSUCC", + " uchar n_succ; /* nr of successor states */", + " #endif", + " #if defined(FULLSTACK) && defined(MA) && !defined(BFS)", + " uchar proviso;", + " #endif", + " #ifndef BFS", + " uchar o_n, o_ot; /* to save locals */", + " #endif", + " uchar o_m;", + " #ifdef EVENT_TRACE", + " #if nstates_event<256", + " uchar o_event;", + " #else", + " unsigned short o_event;", + " #endif", + " #endif", + " #ifndef BFS", + " short o_To;", + " #if defined(T_RAND) || defined(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)) || defined(BFS) || (NCORE>1)", + " H_el *ostate; /* pointer to stored state */", + " #endif", + /* CNTRSTACK when !NOREDUCE && BITSTATE && SAFETY && WS<=4, uses LL[] */ + " #if defined(CNTRSTACK) && !defined(BFS)", + " long j6, j7;", + " #endif", + " Trans *o_t;", /* transition fct, next state */ + + " #if !defined(BFS) && !defined(TRIX_ORIG)", + " char *p_bup;", + " char *q_bup;", + " #endif", + + " #ifdef BCS", + " unsigned short sched_limit;", + " unsigned char bcs; /* phase 1 or 2, or forced 4 */", + " unsigned char b_pno; /* preferred pid */", + " #endif", + + " #ifdef P_RAND", /* process scheduling randomization */ + " unsigned char p_left; /* nr of procs left to explore */", + " short p_skip; /* to find starting point in list */", + " #endif", + + " #ifdef HAS_SORTED", + " short ipt;", /* insertion slot in q */ + " #endif", + " #ifdef HAS_PRIORITY", + " short o_priority;", + " #endif", + " union {", + " int oval;", /* single backup value of variable */ + " int *ovals;", /* ptr to multiple values */ + " } bup;", + "}; /* end of struct Trail */", + "", + "#ifdef BFS", /* breadth-first search */ + " #define Q_PROVISO", + " #ifndef INLINE_REV", + " #define INLINE_REV", + " #endif", + "", + "typedef struct SV_Hold {", + " State *sv;", + " #ifndef BFS_PAR", + " int sz;", + " #endif", + " struct SV_Hold *nxt;", + "} SV_Hold;", + "#if !defined(BFS_PAR) || NRUNS>0", + " typedef struct EV_Hold {", + " #if !defined(BFS_PAR) || (!defined(NOCOMP) && !defined(HC) && NRUNS>0)", + " char *sv; /* Mask */", + " #endif", + " #if VECTORSZ<65536", + " ushort sz; /* vsize */", + " #else", + " ulong sz;", + " #endif", + " #ifdef BFS_PAR", + " uchar owner;", + " #endif", + " uchar nrpr;", + " uchar nrqs;", + " #if !defined(BFS_PAR) || (!defined(TRIX) && NRUNS>0)", + " char *po, *qo;", + " char *ps, *qs;", + " #endif", + " struct EV_Hold *nxt;", + " } EV_Hold;", + "#endif", + "typedef struct BFS_State {", + " #ifdef BFS_PAR", + " BFS_Trail *t_info;", + " State *osv;", + " #else", + " Trail *frame;", + " SV_Hold *onow;", + " #endif", + " #if !defined(BFS_PAR) || NRUNS>0", + " EV_Hold *omask;", + " #endif", + " #if defined(Q_PROVISO) && !defined(NOREDUCE)", + " H_el *lstate;", + " #endif", + " #if !defined(BFS_PAR) || SYNC>0", + " short boq;", + " #endif", + " #ifdef VERBOSE", + " ulong nr;", + " #endif", + " #ifndef BFS_PAR", /* new 6.2.4, 3 dec 2012 */ + " struct BFS_State *nxt;", + " #endif", + "} BFS_State;", + "#endif\n", 0, }; -static char *SvMap[] = { +static const char *SvMap[] = { "void", "to_compile(void)", - "{ char ctd[1024], carg[64];", + "{ char ctd[2048], carg[128];", "#ifdef BITSTATE", " strcpy(ctd, \"-DBITSTATE \");", "#else", " strcpy(ctd, \"\");", "#endif", + "#ifdef BFS_PAR", + " strcat(ctd, \"-DBFS_PAR \");", + "#endif", "#ifdef NOVSZ", " strcat(ctd, \"-DNOVSZ \");", "#endif", + "#ifdef RHASH", + " strcat(ctd, \"-DRHASH \");", + "#else", + " #ifdef PERMUTED", + " strcat(ctd, \"-DPERMUTED \");", + " #endif", + "#endif", + "#ifdef P_REVERSE", + " strcat(ctd, \"-DP_REVERSE \");", + "#endif", + "#ifdef T_REVERSE", + " strcat(ctd, \"-DT_REVERSE \");", + "#endif", + "#ifdef T_RAND", + " #if T_RAND>0", + " sprintf(carg, \"-DT_RAND=%%d \", T_RAND);", + " strcat(ctd, carg);", + " #else", + " strcat(ctd, \"-DT_RAND \");", + " #endif", + "#endif", + "#ifdef P_RAND", + " #if P_RAND>0", + " sprintf(carg, \"-DP_RAND=%%d \", P_RAND);", + " strcat(ctd, carg);", + " #else", + " strcat(ctd, \"-DP_RAND \");", + " #endif", + "#endif", + "#ifdef BCS", + " sprintf(carg, \"-DBCS=%%d \", BCS);", + " strcat(ctd, carg);", + "#endif", + "#ifdef BFS", + " strcat(ctd, \"-DBFS \");", + "#endif", "#ifdef MEMLIM", " sprintf(carg, \"-DMEMLIM=%%d \", MEMLIM);", " strcat(ctd, carg);", @@ -867,20 +1464,8 @@ static char *SvMap[] = { "#ifdef VAR_RANGES", " strcat(ctd, \"-DVAR_RANGES \");", "#endif", - "#ifdef HC0", - " strcat(ctd, \"-DHC0 \");", - "#endif", - "#ifdef HC1", - " strcat(ctd, \"-DHC1 \");", - "#endif", - "#ifdef HC2", - " strcat(ctd, \"-DHC2 \");", - "#endif", - "#ifdef HC3", - " strcat(ctd, \"-DHC3 \");", - "#endif", - "#ifdef HC4", - " strcat(ctd, \"-DHC4 \");", + "#ifdef HC", + " strcat(ctd, \"-DHC \");", "#endif", "#ifdef CHECK", " strcat(ctd, \"-DCHECK \");", @@ -888,6 +1473,9 @@ static char *SvMap[] = { "#ifdef CTL", " strcat(ctd, \"-DCTL \");", "#endif", + "#ifdef TRIX", + " strcat(ctd, \"-DTRIX \");", + "#endif", "#ifdef NIBIS", " strcat(ctd, \"-DNIBIS \");", "#endif", @@ -903,9 +1491,6 @@ static char *SvMap[] = { "#ifdef PRINTF", " strcat(ctd, \"-DPRINTF \");", "#endif", - "#ifdef OTIM", - " strcat(ctd, \"-DOTIM \");", - "#endif", "#ifdef COLLAPSE", " strcat(ctd, \"-DCOLLAPSE \");", "#endif", @@ -916,7 +1501,7 @@ static char *SvMap[] = { "#ifdef SVDUMP", " strcat(ctd, \"-DSVDUMP \");", "#endif", - "#ifdef VECTORSZ", + "#if defined(VECTORSZ) && !defined(TRIX)", " if (VECTORSZ != 1024)", " { sprintf(carg, \"-DVECTORSZ=%%d \", VECTORSZ);", " strcat(ctd, carg);", @@ -931,8 +1516,31 @@ static char *SvMap[] = { "#ifdef SDUMP", " strcat(ctd, \"-DSDUMP \");", "#endif", - "#ifdef COVEST", - " strcat(ctd, \"-DCOVEST \");", + "#if NCORE>1", + " sprintf(carg, \"-DNCORE=%%d \", NCORE);", + " strcat(ctd, carg);", + "#endif", + "#ifdef VMAX", + " if (VMAX != 256)", + " { sprintf(carg, \"-DVMAX=%%d \", VMAX);", + " strcat(ctd, carg);", + " }", + "#endif", + "#ifdef PMAX", + " if (PMAX != 16)", + " { sprintf(carg, \"-DPMAX=%%d \", PMAX);", + " strcat(ctd, carg);", + " }", + "#endif", + "#ifdef QMAX", + " if (QMAX != 16)", + " { sprintf(carg, \"-DQMAX=%%d \", QMAX);", + " strcat(ctd, carg);", + " }", + "#endif", + "#ifdef SET_WQ_SIZE", + " sprintf(carg, \"-DSET_WQ_SIZE=%%d \", SET_WQ_SIZE);", + " strcat(ctd, carg);", "#endif", " printf(\"Compiled as: cc -o pan %%span.c\\n\", ctd);", "}", diff --git a/sys/src/cmd/spin/pangen4.c b/sys/src/cmd/spin/pangen4.c index 777371fc7..61d6dee3b 100644 --- a/sys/src/cmd/spin/pangen4.c +++ b/sys/src/cmd/spin/pangen4.c @@ -1,13 +1,10 @@ /***** spin: pangen4.c *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #include "spin.h" #include "y.tab.h" @@ -17,7 +14,7 @@ extern Queue *qtab; extern Symbol *Fname; extern int lineno, m_loss, Pid, eventmapnr, multi_oval; extern short nocast, has_provided, has_sorted; -extern char *R13[], *R14[], *R15[]; +extern const char *R13[], *R14[], *R15[]; static void check_proc(Lextok *, int); @@ -44,7 +41,7 @@ undostmnt(Lextok *now, int m) case FULL: case EMPTY: case 'R': case NFULL: case NEMPTY: case ENABLED: case '?': case PC_VAL: case '^': - case C_EXPR: + case C_EXPR: case GET_P: case NONPROGRESS: putstmnt(tb, now, m); break; @@ -153,7 +150,14 @@ undostmnt(Lextok *now, int m) fprintf(tb, "p_restor(II);\n\t\t"); break; + case SET_P: + fprintf(tb, "((P0 *)pptr((trpt->o_priority >> 8)))"); + fprintf(tb, "->_priority = trpt->o_priority & 255"); + break; + case ASGN: + if (check_track(now) == STRUCT) { break; } + nocast=1; putstmnt(tb,now->lft,m); nocast=0; fprintf(tb, " = trpt->bup.oval"); if (multi_oval > 0) @@ -307,6 +311,8 @@ genunio(void) ntimes(tc, 0, 1, R15); } +extern void explain(int); + int proper_enabler(Lextok *n) { @@ -317,15 +323,19 @@ proper_enabler(Lextok *n) case LEN: case 'R': case NAME: has_provided = 1; - if (strcmp(n->sym->name, "_pid") == 0) + if (strcmp(n->sym->name, "_pid") == 0 + || strcmp(n->sym->name, "_priority") == 0) return 1; return (!(n->sym->context)); - case CONST: case TIMEOUT: + case C_EXPR: + case CONST: + case TIMEOUT: has_provided = 1; return 1; case ENABLED: case PC_VAL: + case GET_P: /* not SET_P */ return proper_enabler(n->lft); case '!': case UMIN: case '~': @@ -335,10 +345,14 @@ proper_enabler(Lextok *n) case '%': case LT: case GT: case '&': case '^': case '|': case LE: case GE: case NE: case '?': case EQ: case OR: case AND: case LSHIFT: - case RSHIFT: case 'c': + case RSHIFT: case 'c': /* case ',': */ return proper_enabler(n->lft) && proper_enabler(n->rgt); + default: break; } + printf("spin: saw "); + explain(n->ntyp); + printf("\n"); return 0; } diff --git a/sys/src/cmd/spin/pangen4.h b/sys/src/cmd/spin/pangen4.h index d80bdeaac..d5ceaa0f4 100644 --- a/sys/src/cmd/spin/pangen4.h +++ b/sys/src/cmd/spin/pangen4.h @@ -1,24 +1,21 @@ /***** spin: pangen4.h *****/ -/* Copyright (c) 1997-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://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 + * sharing tree data structures and graph-encoded sets by J-Ch. Gregoire + * (INRS Telecom, Quebec, Canada) and D.Zampunieris (Univ.Namur, Belgium) + * The splay routine code included here is based on the public domain + * version written by D. Sleator in 1992. + */ -/* 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 */ -/* sharing tree data structures and graph-encoded sets by J-Ch. Gregoire */ -/* (INRS Telecom, Quebec, Canada) and D.Zampunieris (Univ.Namur, Belgium) */ - -/* The splay routine code included here is based on the public domain */ -/* version written by D. Sleator in 1992. */ - -static char *Dfa[] = { +static const char *Dfa[] = { "#ifdef MA", +#if 0 "/*", "#include ", "#define uchar unsigned char", @@ -26,6 +23,7 @@ static char *Dfa[] = { "#define ulong unsigned long", "#define ushort unsigned short", "", +#endif "#define TWIDTH 256", "#define HASH(y,n) (n)*(((long)y))", "#define INRANGE(e,h) ((h>=e->From && h<=e->To)||(e->s==1 && e->S==h))", @@ -466,7 +464,7 @@ static char *Dfa[] = { " for (j = 0; j < TWIDTH; j++)", " for (i = 0; i < dfa_depth+1; i++)", " cnt += tree_stats(layers[i*TWIDTH+j]);", - " printf(\"Minimized Automaton:\t%%6d nodes and %%6g edges\\n\",", + " printf(\"Minimized Automaton:\t%%6lu nodes and %%6g edges\\n\",", " nr_states, cnt);", "}", "", diff --git a/sys/src/cmd/spin/pangen5.c b/sys/src/cmd/spin/pangen5.c index 25885e19c..1e276df73 100644 --- a/sys/src/cmd/spin/pangen5.c +++ b/sys/src/cmd/spin/pangen5.c @@ -1,13 +1,10 @@ /***** spin: pangen5.c *****/ -/* Copyright (c) 1999-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #include "spin.h" #include "y.tab.h" @@ -140,6 +137,7 @@ eligible(FSM_trans *v) || lt->ntyp == C_CODE || lt->ntyp == C_EXPR || has_lab(el, 0) /* any label at all */ + || lt->ntyp == SET_P /* to prevent multiple set_p merges */ || lt->ntyp == DO || lt->ntyp == UNLESS @@ -211,13 +209,18 @@ popbuild(void) static int build_step(FSM_trans *v) { FSM_state *f; - Element *el = v->step; + Element *el; #if 0 Lextok *lt = ZN; #endif - int st = v->to; + int st; int r; + if (!v) return -1; + + el = v->step; + st = v->to; + if (!el) return -1; if (v->step->merge) @@ -234,9 +237,7 @@ build_step(FSM_trans *v) lt = v->step->n; if (verbose&32) { if (++howdeep == 1) - printf("spin: %s, line %3d, merge:\n", - lt->fn->name, - lt->ln); + printf("spin: %s:%d, merge:\n", lt->fn->name, lt->ln); printf("\t[%d] \t", howdeep, el->seqno); comment(stdout, lt, 0); printf(";\n"); @@ -257,7 +258,7 @@ build_step(FSM_trans *v) } static void -FSM_MERGER(char *pname_unused) /* find candidates for safely merging steps */ +FSM_MERGER(/* char *pname */ void) /* find candidates for safely merging steps */ { FSM_state *f, *g; FSM_trans *t; Lextok *lt; @@ -281,14 +282,14 @@ FSM_MERGER(char *pname_unused) /* find candidates for safely merging steps */ continue; g = fsm_tbl[t->to]; - if (!eligible(g->t)) + if (!g || !eligible(g->t)) { #define SINGLES #ifdef SINGLES t->step->merge_single = t->to; #if 0 if ((verbose&32)) - { printf("spin: %s, line %3d, merge_single:\n\t\t", + { printf("spin: %s:%d, merge_single:\n\t\t", t->step->n->fn->name, t->step->n->ln, t->step->seqno); @@ -321,14 +322,17 @@ FSM_MERGER(char *pname_unused) /* find candidates for safely merging steps */ 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 + an rv send operation ('s') 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 + the same is not true for non-rv send operations; + 6.2.2: + RUN statements can start a new process at a higher priority level + which interferes with statement merging, so it too is not a suitable + merge target #endif - if (lt->ntyp == 'c' /* potentially blocking stmnts */ + if ((lt->ntyp == 'c' && !any_oper(lt->lft, RUN)) /* 2nd clause 6.2.2 */ || lt->ntyp == 'r' || (lt->ntyp == 's' && u_sync == 0)) /* added !u_sync in 4.1.3 */ { if (!canfill_in(t)) /* atomic, non-global, etc. */ @@ -346,9 +350,8 @@ FSM_MERGER(char *pname_unused) /* find candidates for safely merging steps */ #if 0 if ((verbose&32) && t->step->merge_start) - { printf("spin: %s, line %3d, merge_START:\n\t\t", - lt->fn->name, - lt->ln, + { printf("spin: %s:%d, merge_START:\n\t\t", + lt->fn->name, lt->ln, t->step->seqno); comment(stdout, lt, 0); printf(";\n"); @@ -532,6 +535,7 @@ ana_var(FSM_trans *t, Lextok *now, int usage) if (now->sym->name[0] == '_' && (strcmp(now->sym->name, "_") == 0 || strcmp(now->sym->name, "_pid") == 0 + || strcmp(now->sym->name, "_priority") == 0 || strcmp(now->sym->name, "_last") == 0)) return; @@ -588,10 +592,17 @@ ana_stmnt(FSM_trans *t, Lextok *now, int usage) case C_EXPR: break; + case ',': /* reached with SET_P and array initializers */ + if (now->lft && now->lft->rgt) + { ana_stmnt(t, now->lft->rgt, RVAL); + } + break; + case '!': case UMIN: case '~': case ENABLED: + case GET_P: case PC_VAL: case LEN: case FULL: @@ -603,6 +614,11 @@ ana_stmnt(FSM_trans *t, Lextok *now, int usage) ana_stmnt(t, now->lft, RVAL); break; + case SET_P: + ana_stmnt(t, now->lft, RVAL); /* ',' */ + ana_stmnt(t, now->lft->rgt, RVAL); + break; + case '/': case '*': case '-': @@ -626,8 +642,11 @@ ana_stmnt(FSM_trans *t, Lextok *now, int usage) break; case ASGN: + if (check_track(now) == STRUCT) { break; } + ana_stmnt(t, now->lft, LVAL); - ana_stmnt(t, now->rgt, RVAL); + if (now->rgt->ntyp) + ana_stmnt(t, now->rgt, RVAL); break; case PRINT: @@ -679,7 +698,8 @@ ana_stmnt(FSM_trans *t, Lextok *now, int usage) break; default: - printf("spin: bad node type %d line %d (ana_stmnt)\n", now->ntyp, now->ln); + printf("spin: %s:%d, bad node type %d (ana_stmnt)\n", + now->fn->name, now->ln, now->ntyp); fatal("aborting", (char *) 0); } } @@ -692,10 +712,7 @@ ana_src(int dataflow, int merger) /* called from main.c and guided.c */ int counter = 1; #endif for (p = rdy; p; p = p->nxt) - { if (p->tn == eventmapnr - || p->tn == claimnr) - continue; - + { ana_seq(p->s); fsm_table(); @@ -711,7 +728,7 @@ ana_src(int dataflow, int merger) /* called from main.c and guided.c */ { FSM_ANA(); } if (merger) - { FSM_MERGER(p->n->name); + { FSM_MERGER(/* p->n->name */); huntele(e, e->status, -1)->merge_in = 1; /* start-state */ #if 0 printf("\n"); @@ -726,8 +743,7 @@ ana_src(int dataflow, int merger) /* called from main.c and guided.c */ { if (!(e->status&DONE) && (verbose&32)) { printf("unreachable code: "); - printf("%s, line %3d: ", - e->n->fn->name, e->n->ln); + printf("%s:%3d ", e->n->fn->name, e->n->ln); comment(stdout, e->n, 0); printf("\n"); } @@ -735,7 +751,7 @@ ana_src(int dataflow, int merger) /* called from main.c and guided.c */ } if (export_ast) { AST_slice(); - exit(0); + alldone(0); /* changed in 5.3.0: was exit(0) */ } } @@ -831,9 +847,15 @@ ana_seq(Sequence *s) { if (e->n->ntyp == GOTO) { g = get_lab(e->n, 1); g = huntele(g, e->status, -1); + if (!g) + { fatal("unexpected error 2", (char *) 0); + } To = g->seqno; } else if (e->nxt) { g = huntele(e->nxt, e->status, -1); + if (!g) + { fatal("unexpected error 3", (char *) 0); + } To = g->seqno; } else To = 0; diff --git a/sys/src/cmd/spin/pangen5.h b/sys/src/cmd/spin/pangen5.h index 5313e73b2..b19a95232 100644 --- a/sys/src/cmd/spin/pangen5.h +++ b/sys/src/cmd/spin/pangen5.h @@ -1,15 +1,12 @@ /***** spin: pangen5.h *****/ -/* Copyright (c) 1997-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ -static char *Xpt[] = { +static const char *Xpt[] = { "#if defined(MA) && (defined(W_XPT) || defined(R_XPT))", "static Vertex **temptree;", "static char wbuf[4096];", @@ -80,7 +77,7 @@ static char *Xpt[] = { " int i, j; uchar c;", " static uchar xwarned = 0;", "", - " sprintf(nm, \"%%s.xpt\", Source);", + " sprintf(nm, \"%%s.xpt\", PanSource);", " if ((fd = creat(nm, 0666)) <= 0)", " if (!xwarned)", " { xwarned = 1;", @@ -136,7 +133,7 @@ static char *Xpt[] = { " stacker[dfa_depth-1] = 0; r = dfa_store(stacker);", " stacker[dfa_depth-1] = 4; j = dfa_member(dfa_depth-1);", " if (r != 1 || j != 0)", - " { printf(\"%%d: \", stackcnt);", + " { printf(\"%%lu: \", stackcnt);", " for (i = 0; i < dfa_depth; i++)", " printf(\"%%d,\", stacker[i]);", " printf(\" -- not a stackstate \\n\", r, j);", @@ -372,7 +369,7 @@ static char *Xpt[] = { " int i, j;", "", " wcnt = 0;", - " sprintf(nm, \"%%s.xpt\", Source);", + " sprintf(nm, \"%%s.xpt\", PanSource);", " if ((fd = open(nm, 0)) < 0) /* O_RDONLY */", " Uerror(\"cannot open checkpoint file\");", "", @@ -416,7 +413,7 @@ static char *Xpt[] = { " x_cleanup(d);", " close(fd);", "", - " printf(\"pan: removed %%d stackstates\\n\", stackcnt);", + " printf(\"pan: removed %%lu stackstates\\n\", stackcnt);", " nstates -= (double) stackcnt;", "}", "#endif", diff --git a/sys/src/cmd/spin/pangen6.c b/sys/src/cmd/spin/pangen6.c index 50b587749..34b66ef2c 100644 --- a/sys/src/cmd/spin/pangen6.c +++ b/sys/src/cmd/spin/pangen6.c @@ -1,20 +1,10 @@ /***** 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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #include "spin.h" #include "y.tab.h" @@ -90,7 +80,6 @@ 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; @@ -145,7 +134,7 @@ name_def_indices(Lextok *n, int code) { if (!n || !n->sym) return; - if (n->sym->nel != 1) + if (n->sym->nel > 1 || n->sym->isarray) def_use(n->lft, code); /* process the index */ if (n->sym->type == STRUCT /* and possible deeper ones */ @@ -202,6 +191,8 @@ def_use(Lextok *now, int code) case '~': case 'c': case ENABLED: + case SET_P: + case GET_P: case ASSERT: case EVAL: def_use(now->lft, USE|code); @@ -503,7 +494,7 @@ AST_mutual(Lextok *a, Lextok *b, int toplevel) if (strcmp(as->name, bs->name) != 0) return 0; - if (as->type == STRUCT && a->rgt && b->rgt) + if (as->type == STRUCT && a->rgt && b->rgt) /* we know that a and b are not null */ return AST_mutual(a->rgt->lft, b->rgt->lft, 0); return 1; @@ -545,14 +536,14 @@ AST_other(AST *a) /* check chan params in asgns and recvs */ 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 */ + { int aa = AST_nrpar(cl->s); + int bb = AST_nrpar(t->step->n); + if (aa != bb) /* 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 */ + aa = AST_ord(cl->s, cl->n); + bb = AST_ord(t->step->n, u->n); + if (aa != bb) /* same position in parlist */ continue; AST_add_alias(cl->n, 4); /* RCV assume possible match */ @@ -692,9 +683,7 @@ AST_relevant(Lextok *n) } 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) + { if (a->p->b != N_CLAIM && a->p->b != E_TRACE && a->p->b != N_TRACE) for (f = a->fsm; f; f = f->nxt) for (t = f->t; t; t = t->nxt) { if (!(t->relevant&1)) @@ -786,10 +775,8 @@ AST_tagruns(void) */ 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) + { if (a->p->b == N_CLAIM || a->p->b == I_PROC + || a->p->b == E_TRACE || a->p->b == N_TRACE) { a->relevant |= 1; /* the proctype is relevant */ continue; } @@ -823,9 +810,9 @@ AST_report(AST *a, Element *e) /* ALSO deduce irrelevant vars */ 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, + printf(" %s:%d (state %d)", e->n?e->n->fn->name:"-", + e->n?e->n->ln:-1, e->seqno); printf(" ["); comment(stdout, e->n, 0); @@ -1016,7 +1003,8 @@ name_AST_track(Lextok *n, int code) printf(" -- %d\n", code); #endif if (in_recv && (code&DEF) && (code&USE)) - { printf("spin: error: DEF and USE of same var in rcv stmnt: "); + { printf("spin: %s:%d, error: DEF and USE of same var in rcv stmnt: ", + n->fn->name, n->ln); AST_var(n, n->sym, 1); printf(" -- %d\n", code); nr_errs++; @@ -1065,6 +1053,8 @@ AST_track(Lextok *now, int code) /* called from main.c */ case '~': case 'c': case ENABLED: + case SET_P: + case GET_P: case ASSERT: AST_track(now->lft, USE|code); break; @@ -1075,8 +1065,8 @@ AST_track(Lextok *now, int code) /* called from main.c */ case NAME: name_AST_track(now, code); - if (now->sym->nel != 1) - AST_track(now->lft, USE|code); /* index */ + if (now->sym->nel > 1 || now->sym->isarray) + AST_track(now->lft, USE); /* index, was USE|code */ break; case 'R': @@ -1569,7 +1559,8 @@ AST_ctrl(AST *a) { t->relevant &= ~2; /* clear mark */ if (verbose&32) { printf("\t\tnomark "); - comment(stdout, t->step->n, 0); + if (t->step && t->step->n) + comment(stdout, t->step->n, 0); printf("\n"); } } } @@ -1601,7 +1592,8 @@ AST_ctrl(AST *a) t->relevant |= 2; /* lift */ if (verbose&32) { printf("\t\t\tliftmark "); - comment(stdout, t->step->n, 0); + if (t->step && t->step->n) + comment(stdout, t->step->n, 0); printf("\n"); } AST_spread(a, t->to); /* and spread to all guards */ @@ -1621,10 +1613,9 @@ 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); + { if (a->p->b != N_CLAIM && a->p->b != E_TRACE && a->p->b != N_TRACE) + { AST_ctrl(a); + } } } static void @@ -1634,9 +1625,7 @@ AST_prelabel(void) 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) + { if (a->p->b != N_CLAIM && a->p->b != E_TRACE && a->p->b != N_TRACE) for (f = a->fsm; f; f = f->nxt) for (t = f->t; t; t = t->nxt) { if (t->step @@ -1692,8 +1681,7 @@ AST_slice(void) int spurious = 0; if (!slicer) - { non_fatal("no slice criteria (or no claim) specified", - (char *) 0); + { printf("spin: warning: no slice criteria found (no assertions and no claim)\n"); spurious = 1; } AST_dorelevant(); /* mark procs refered to in remote refs */ @@ -1730,9 +1718,7 @@ 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) + if (p->b != N_CLAIM && p->b != E_TRACE && p->b != N_TRACE) { n_ast = (AST *) emalloc(sizeof(AST)); n_ast->p = p; n_ast->i_st = start_state; @@ -1809,12 +1795,10 @@ AST_par_init(void) /* parameter passing -- hidden assignments */ 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 */ - + { if (a->p->b == N_CLAIM || a->p->b == I_PROC + || a->p->b == E_TRACE || a->p->b == N_TRACE) + { continue; /* has no params */ + } cnt = 0; for (f = a->p->p; f; f = f->rgt) /* types */ for (t = f->lft; t; t = t->rgt) /* formals */ @@ -1845,9 +1829,8 @@ AST_var_init(void) /* initialized vars (not chans) - hidden assignments */ } } 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 */ + { if (a->p->b != N_CLAIM + && a->p->b != E_TRACE && a->p->b != N_TRACE) /* has no locals */ for (walk = all_names; walk; walk = walk->next) { sp = walk->entry; if (sp @@ -1995,7 +1978,7 @@ subgraph(AST *a, FSM_state *f, int out) h = fsm_tbl[out]; i = f->from / BPW; - j = f->from % BPW; + j = f->from % BPW; /* assert(j <= 32); else lshift undefined? */ g = h->mod; if (verbose&32) @@ -2023,28 +2006,30 @@ act_dom(AST *a) 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. */ - + { 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. */ - + { continue; /* c. */ + } i = cnt / BPW; - j = cnt % BPW; + j = cnt % BPW; /* assert(j <= 32); */ if (!(f->dom[i]&(1<t, i = 0; t; t = t->nxt) - i += fsm_tbl[t->to]->seen; + { i += fsm_tbl[t->to]->seen; + } if (i <= 1) - continue; /* b. */ - + { continue; /* b. */ + } if (f->mod) /* final check in 2nd phase */ - subgraph(a, f, cnt); /* possible entry-exit pair */ - } - } + { subgraph(a, f, cnt); /* possible entry-exit pair */ + } } } } static void @@ -2178,27 +2163,26 @@ init_dom(AST *a) for (f = a->fsm; f; f = f->nxt) { if (!f->seen) continue; - f->dom = (ulong *) - emalloc(a->nwords * sizeof(ulong)); + f->dom = (ulong *) emalloc(a->nwords * sizeof(ulong)); if (f->from == a->i_st) { i = a->i_st / BPW; - j = a->i_st % BPW; + j = a->i_st % BPW; /* assert(j <= 32); */ f->dom[i] = (1<nwords; i++) - f->dom[i] = (ulong) ~0; /* all 1's */ - + { f->dom[i] = (ulong) ~0; /* all 1's */ + } if (a->nstates % BPW) for (i = (a->nstates % BPW); i < (int) BPW; i++) - f->dom[a->nwords-1] &= ~(1<dom[a->nwords-1] &= ~(1<< ((ulong) i)); /* clear tail */ + } for (cnt = 0; cnt < a->nstates; cnt++) - if (!fsm_tbl[cnt]->seen) + { if (!fsm_tbl[cnt]->seen) { i = cnt / BPW; - j = cnt % BPW; - f->dom[i] &= ~(1<dom[i] &= ~(1<< ((ulong) j)); + } } } } } static int @@ -2226,7 +2210,7 @@ dom_perculate(AST *a, FSM_state *f) } i = f->from / BPW; - j = f->from % BPW; + j = f->from % BPW; /* assert(j <= 32); */ ndom[i] |= (1<nwords; i++) @@ -2261,6 +2245,7 @@ AST_dominant(void) FSM_trans *t; AST *a; int oi; + static FSM_state no_state; #if 0 find dominators Aho, Sethi, & Ullman, Compilers - principles, techniques, and tools diff --git a/sys/src/cmd/spin/pangen6.h b/sys/src/cmd/spin/pangen6.h new file mode 100644 index 000000000..09d158b57 --- /dev/null +++ b/sys/src/cmd/spin/pangen6.h @@ -0,0 +1,2878 @@ +/***** spin: pangen6.h *****/ + +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ + +static const char *Code2e[] = { + "#if (NCORE>1 || defined(BFS_PAR)) && !defined(WIN32) && !defined(WIN64)", + " /* Test and Set assembly code */", + " #if defined(i386) || defined(__i386__) || defined(__x86_64__)", + " int", + " tas(volatile int *s) /* tested */", + " { int r;", + " __asm__ __volatile__(", + " \"xchgl %%0, %%1 \\n\\t\"", + " : \"=r\"(r), \"=m\"(*s)", + " : \"0\"(1), \"m\"(*s)", + " : \"memory\");", + " ", + " return r;", + " }", + " #elif defined(__arm__)", + " int", + " tas(volatile int *s) /* not tested */", + " { int r = 1;", + " __asm__ __volatile__(", + " \"swpb %%0, %%0, [%%3] \\n\"", + " : \"=r\"(r), \"=m\"(*s)", + " : \"0\"(r), \"r\"(s));", + "", + " return r;", + " }", + " #elif defined(sparc) || defined(__sparc__)", + " int", + " tas(volatile int *s) /* not tested */", + " { int r = 1;", + " __asm__ __volatile__(", + " \" ldstub [%%2], %%0 \\n\"", + " : \"=r\"(r), \"=m\"(*s)", + " : \"r\"(s));", + "", + " return r;", + " }", + " #elif defined(ia64) || defined(__ia64__)", + " /* Intel Itanium */", + " int", + " tas(volatile int *s) /* tested */", + " { long int r;", + " __asm__ __volatile__(", + " \" xchg4 %%0=%%1,%%2 \\n\"", + " : \"=r\"(r), \"+m\"(*s)", + " : \"r\"(1)", + " : \"memory\");", + " return (int) r;", + " }", + " #elif defined(__powerpc64__)", + " int", + " tas(volatile int *s) /* courtesy srirajpaul */", + " { int r;", + " #if 1", + " r = __sync_lock_test_and_set();", + " #else", + " /* xlc compiler only */", + " r = __fetch_and_or(s, 1);", + " __isync();", + " #endif", + " return r;", + " }", + " #else", + " #error missing definition of test and set operation for this platform", + " #endif", + "", + " #ifndef NO_CAS", /* linux, windows */ + " #define cas(a,b,c) __sync_bool_compare_and_swap(a,b,c)", + " #else", + " int", /* workaround if the above is not available */ + " cas(volatile uint32_t *a, uint32_t b, uint32_t c)", + " { static volatile int cas_lock;", + " while (tas(&cas_lock) != 0) { ; }", + " if (*a == b)", + " { *a = c;", + " cas_lock = 0;", + " return 1;", + " }", + " cas_lock = 0;", + " return 0;", + " }", + " #endif", + "#endif", + 0, +}; + +static const char *Code2c[] = { /* multi-core option - Spin 5.0 and later */ + "#if NCORE>1", + "#if defined(WIN32) || defined(WIN64)", + " #ifndef _CONSOLE", + " #define _CONSOLE", + " #endif", + " #ifdef WIN64", + " #undef long", + " #endif", + " #include ", + "/*", + " #ifdef WIN64", + " #define long long long", + " #endif", + "*/", + "#else", + " #include ", + " #include ", + " #include ", + "#endif", + "", + "/* code common to cygwin/linux and win32/win64: */", + "", + "#ifdef VERBOSE", + " #define VVERBOSE (1)", + "#else", + " #define VVERBOSE (0)", + "#endif", + "", + "/* the following values must be larger than 256 and must fit in an int */", + "#define QUIT 1024 /* terminate now command */", + "#define QUERY 512 /* termination status query message */", + "#define QUERY_F 513 /* query failed, cannot quit */", + "", + "#define GN_FRAMES (int) (GWQ_SIZE / (double) sizeof(SM_frame))", + "#define LN_FRAMES (int) (LWQ_SIZE / (double) sizeof(SM_frame))", + "", + "#ifndef VMAX", + " #define VMAX VECTORSZ", + "#endif", + "#ifndef PMAX", + " #define PMAX 64", + "#endif", + "#ifndef QMAX", + " #define QMAX 64", + "#endif", + "", + "#if VECTORSZ>32000", + " #define OFFT int", + "#else", + " #define OFFT short", + "#endif", + "", + "#ifdef SET_SEG_SIZE", + " /* no longer useful -- being recomputed for local heap size anyway */", + " double SEG_SIZE = (((double) SET_SEG_SIZE) * 1048576.);", + "#else", + " double SEG_SIZE = (1048576.*1024.); /* 1GB default shared memory pool segments */", + "#endif", + "", + "double LWQ_SIZE = 0.; /* initialized in main */", + "", + "#ifdef SET_WQ_SIZE", + " #ifdef NGQ", + " #warning SET_WQ_SIZE applies to global queue -- ignored", + " double GWQ_SIZE = 0.;", + " #else", + " double GWQ_SIZE = (((double) SET_WQ_SIZE) * 1048576.);", + " /* must match the value in pan_proxy.c, if used */", + " #endif", + "#else", + " #ifdef NGQ", + " double GWQ_SIZE = 0.;", + " #else", + " double GWQ_SIZE = (128.*1048576.); /* 128 MB default queue sizes */", + " #endif", + "#endif", + "", + "/* Crash Detection Parameters */", + "#ifndef ONESECOND", + " #define ONESECOND (1<<25)", /* name is somewhat of a misnomer */ + "#endif", + "#ifndef SHORT_T", + " #define SHORT_T (0.1)", + "#endif", + "#ifndef LONG_T", + " #define LONG_T (600)", + "#endif", + "", + "double OneSecond = (double) (ONESECOND); /* waiting for a free slot -- checks crash */", + "double TenSeconds = 10. * (ONESECOND); /* waiting for a lock -- check for a crash */", + "", + "/* Termination Detection Params -- waiting for new state input in Get_Full_Frame */", + "double Delay = ((double) SHORT_T) * (ONESECOND); /* termination detection trigger */", + "double OneHour = ((double) LONG_T) * (ONESECOND); /* timeout termination detection */", + "", + "typedef struct SM_frame SM_frame;", + "typedef struct SM_results SM_results;", + "typedef struct sh_Allocater sh_Allocater;", + "", + "struct SM_frame { /* about 6K per slot */", + " volatile int m_vsize; /* 0 means free slot */", + " volatile int m_boq; /* >500 is a control message */", + "#ifdef FULL_TRAIL", + " volatile struct Stack_Tree *m_stack; /* ptr to previous state */", + "#endif", + " volatile uchar m_tau;", + " volatile uchar m_o_pm;", + " volatile int nr_handoffs; /* to compute real_depth */", + " volatile char m_now [VMAX];", + "#if !defined(NOCOMP) && !defined(HC)", + " volatile char m_mask [(VMAX + 7)/8];", + "#endif", + " volatile OFFT m_p_offset[PMAX];", + " volatile OFFT m_q_offset[QMAX];", + " volatile uchar m_p_skip [PMAX];", + " volatile uchar m_q_skip [QMAX];", + "#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)", + " volatile uchar m_c_stack [StackSize];", + /* captures contents of c_stack[] for unmatched objects */ + "#endif", + "};", + "", + "int proxy_pid; /* id of proxy if nonzero -- receive half */", + "int store_proxy_pid;", + "short remote_party;", + "int proxy_pid_snd; /* id of proxy if nonzero -- send half */", + "char o_cmdline[512]; /* to pass options to children */", + "", + "int iamin[CS_NR+NCORE]; /* non-shared */", + "", +"#if defined(WIN32) || defined(WIN64)", + "int tas(volatile LONG *);", + "", + "HANDLE proxy_handle_snd; /* for Windows Create and Terminate */", + "", + "struct sh_Allocater { /* shared memory for states */", + " volatile char *dc_arena; /* to allocate states from */", + " volatile long pattern; /* to detect overruns */", + " volatile long dc_size; /* nr of bytes left */", + " volatile void *dc_start; /* where memory segment starts */", + " volatile void *dc_id; /* to attach, detach, remove shared memory segments */", + " volatile sh_Allocater *nxt; /* linked list of pools */", + "};", + "DWORD worker_pids[NCORE]; /* root mem of pids of all workers created */", + "HANDLE worker_handles[NCORE]; /* for windows Create and Terminate */", + "void * shmid [NR_QS]; /* return value from CreateFileMapping */", + "void * shmid_M; /* shared mem for state allocation in hashtable */", + "", + "#ifdef SEP_STATE", + " void *shmid_X;", + "#else", + " void *shmid_S; /* shared bitstate arena or hashtable */", + "#endif", +"#else", + "int tas(volatile int *);", + "", + "struct sh_Allocater { /* shared memory for states */", + " volatile char *dc_arena; /* to allocate states from */", + " volatile long pattern; /* to detect overruns */", + " volatile long dc_size; /* nr of bytes left */", + " volatile char *dc_start; /* where memory segment starts */", + " volatile int dc_id; /* to attach, detach, remove shared memory segments */", + " volatile sh_Allocater *nxt; /* linked list of pools */", + "};", + "", + "int worker_pids[NCORE]; /* root mem of pids of all workers created */", + "int shmid [NR_QS]; /* return value from shmget */", + "int nibis = 0; /* set after shared mem has been released */", + "int shmid_M; /* shared mem for state allocation in hashtable */", + "#ifdef SEP_STATE", + " long shmid_X;", + "#else", + " int shmid_S; /* shared bitstate arena or hashtable */", + " volatile sh_Allocater *first_pool; /* of shared state memory */", + " volatile sh_Allocater *last_pool;", + "#endif", /* SEP_STATE */ +"#endif", /* WIN32 || WIN64 */ + "", + "struct SM_results { /* for shuttling back final stats */", + " volatile int m_vsize; /* avoid conflicts with frames */", + " volatile int m_boq; /* these 2 fields are not written in record_info */", + " /* probably not all fields really need to be volatile */", + " volatile double m_memcnt;", + " volatile double m_nstates;", + " volatile double m_truncs;", + " volatile double m_truncs2;", + " volatile double m_nShadow;", + " volatile double m_nlinks;", + " volatile double m_ngrabs;", + " volatile double m_nlost;", + " volatile double m_hcmp;", + " volatile double m_frame_wait;", + " volatile int m_hmax;", + " volatile int m_svmax;", + " volatile int m_smax;", + " volatile int m_mreached;", + " volatile int m_errors;", + " volatile int m_VMAX;", + " volatile short m_PMAX;", + " volatile short m_QMAX;", + " volatile uchar m_R; /* reached info for all proctypes */", + "};", + "", + "int core_id = 0; /* internal process nr, to know which q to use */", + "unsigned long nstates_put = 0; /* statistics */", + "unsigned long nstates_get = 0;", + "int query_in_progress = 0; /* termination detection */", + "", + "double free_wait = 0.; /* waiting for a free frame */", + "double frame_wait = 0.; /* waiting for a full frame */", + "double lock_wait = 0.; /* waiting for access to cs */", + "double glock_wait[3]; /* waiting for access to global lock */", + "", + "char *sprefix = \"rst\";", + "uchar was_interrupted, issued_kill, writing_trail;", + "", + "static SM_frame cur_Root; /* current root, to be safe with error trails */", + "", + "SM_frame *m_workq [NR_QS]; /* per cpu work queues + global q */", + "char *shared_mem[NR_QS]; /* return value from shmat */", + "#ifdef SEP_HEAP", + "char *my_heap;", + "long my_size;", + "#endif", + "volatile sh_Allocater *dc_shared; /* assigned at initialization */", + "", + "static int vmax_seen, pmax_seen, qmax_seen;", + "static double gq_tries, gq_hasroom, gq_hasnoroom;", + "", + "volatile int *prfree;", /* [NCORE] */ + "volatile int *prfull;", /* [NCORE] */ + "volatile int *prcnt;", /* [NCORE] */ + "volatile int *prmax;", /* [NCORE] */ + "", + "volatile int *sh_lock; /* mutual exclusion locks - in shared memory */", + "volatile double *is_alive; /* to detect when processes crash */", + "volatile int *grfree, *grfull, *grcnt, *grmax; /* access to shared global q */", + "volatile double *gr_readmiss, *gr_writemiss;", + "static int lrfree; /* used for temporary recording of slot */", + "static int dfs_phase2;", + "", + "void mem_put(int); /* handoff state to other cpu */", + "void mem_put_acc(void); /* liveness mode */", + "void mem_get(void); /* get state from work queue */", + "void sudden_stop(char *);", + "", + "void", + "record_info(SM_results *r)", + "{ int i;", + " uchar *ptr;", + "", + "#ifdef SEP_STATE", + " if (0)", + " { cpu_printf(\"nstates %%g nshadow %%g -- memory %%-6.3f Mb\\n\",", + " nstates, nShadow, memcnt/(1048576.));", + " }", + " r->m_memcnt = 0;", + "#else", + " #ifdef BITSTATE", + " r->m_memcnt = 0; /* it's shared */", + " #endif", + " r->m_memcnt = memcnt;", + "#endif", + " if (a_cycles && core_id == 1)", + " { r->m_nstates = nstates;", + " r->m_nShadow = nstates;", + " } else", + " { r->m_nstates = nstates;", + " r->m_nShadow = nShadow;", + " }", + " r->m_truncs = truncs;", + " r->m_truncs2 = truncs2;", + " r->m_nlinks = nlinks;", + " r->m_ngrabs = ngrabs;", + " r->m_nlost = nlost;", + " r->m_hcmp = hcmp;", + " r->m_frame_wait = frame_wait;", + " r->m_hmax = hmax;", + " r->m_svmax = svmax;", + " r->m_smax = smax;", + " r->m_mreached = mreached;", + " r->m_errors = errors;", + " r->m_VMAX = vmax_seen;", + " r->m_PMAX = (short) pmax_seen;", + " r->m_QMAX = (short) qmax_seen;", + " ptr = (uchar *) &(r->m_R);", + " for (i = 0; i <= _NP_; i++) /* all proctypes */", + " { memcpy(ptr, reached[i], NrStates[i]*sizeof(uchar));", + " ptr += NrStates[i]*sizeof(uchar);", + " }", + " if (verbose>1)", + " { cpu_printf(\"Put Results nstates %%g (sz %%d)\\n\", nstates, ptr - &(r->m_R));", + " }", + "}", + "", + "void snapshot(void);", + "", + "void", + "retrieve_info(SM_results *r)", + "{ int i, j;", + " volatile uchar *ptr;", + "", + " snapshot(); /* for a final report */", + "", + " enter_critical(GLOBAL_LOCK);", + "#ifdef SEP_HEAP", + " if (verbose)", + " { printf(\"cpu%%d: local heap-left %%ld KB (%%d MB)\\n\",", + " core_id, (long) (my_size/1024), (int) (my_size/1048576));", + " }", + "#endif", + " if (verbose && core_id == 0)", + " { printf(\"qmax: \");", + " for (i = 0; i < NCORE; i++)", + " { printf(\"%%d \", prmax[i]);", + " }", + "#ifndef NGQ", + " printf(\"G: %%d\", *grmax);", + "#endif", + " printf(\"\\n\");", + " }", + " leave_critical(GLOBAL_LOCK);", + "", + " memcnt += r->m_memcnt;", + " nstates += r->m_nstates;", + " nShadow += r->m_nShadow;", + " truncs += r->m_truncs;", + " truncs2 += r->m_truncs2;", + " nlinks += r->m_nlinks;", + " ngrabs += r->m_ngrabs;", + " nlost += r->m_nlost;", + " hcmp += r->m_hcmp;", + " /* frame_wait += r->m_frame_wait; */", + " errors += r->m_errors;", + "", + " if (hmax < r->m_hmax) hmax = r->m_hmax;", + " if (svmax < r->m_svmax) svmax = r->m_svmax;", + " if (smax < r->m_smax) smax = r->m_smax;", + " if (mreached < r->m_mreached) mreached = r->m_mreached;", + "", + " if (vmax_seen < r->m_VMAX) vmax_seen = r->m_VMAX;", + " if (pmax_seen < (int) r->m_PMAX) pmax_seen = (int) r->m_PMAX;", + " if (qmax_seen < (int) r->m_QMAX) qmax_seen = (int) r->m_QMAX;", + "", + " ptr = &(r->m_R);", + " for (i = 0; i <= _NP_; i++) /* all proctypes */", + " { for (j = 0; j < NrStates[i]; j++)", + " { if (*(ptr + j) != 0)", + " { reached[i][j] = 1;", + " } }", + " ptr += NrStates[i]*sizeof(uchar);", + " }", + " if (verbose>1)", + " { cpu_printf(\"Got Results (%%d)\\n\", (int) (ptr - &(r->m_R)));", + " snapshot();", + " }", + "}", + "", + "#if !defined(WIN32) && !defined(WIN64)", + "static void", + "rm_shared_segments(void)", + "{ int m;", + " volatile sh_Allocater *nxt_pool;", + " /*", + " * mark all shared memory segments for removal ", + " * the actual removes wont happen intil last process dies or detaches", + " * the shmctl calls can return -1 if not all procs have detached yet", + " */", + " for (m = 0; m < NR_QS; m++) /* +1 for global q */", + " { if (shmid[m] != -1)", + " { (void) shmctl(shmid[m], IPC_RMID, NULL);", + " } }", + "#ifdef SEP_STATE", + " if (shmid_M != -1)", + " { (void) shmctl(shmid_M, IPC_RMID, NULL);", + " }", + "#else", + " if (shmid_S != -1)", + " { (void) shmctl(shmid_S, IPC_RMID, NULL);", + " }", + " for (last_pool = first_pool; last_pool != NULL; last_pool = nxt_pool)", + " { shmid_M = (int) (last_pool->dc_id);", + " nxt_pool = last_pool->nxt; /* as a pre-caution only */", + " if (shmid_M != -1)", + " { (void) shmctl(shmid_M, IPC_RMID, NULL);", + " } }", + "#endif", + "}", + "#endif", + "", + "void", + "sudden_stop(char *s)", + "{ char b[64];", + " int i;", + "", + " printf(\"cpu%%d: stop - %%s\\n\", core_id, s);", + "#if !defined(WIN32) && !defined(WIN64)", + " if (proxy_pid != 0)", + " { rm_shared_segments();", + " }", + "#endif", + " if (search_terminated != NULL)", + " { if (*search_terminated != 0)", + " { if (verbose)", + " { printf(\"cpu%%d: termination initiated (%%d)\\n\",", + " core_id, (int) *search_terminated);", + " }", + " } else", + " { if (verbose)", + " { printf(\"cpu%%d: initiated termination\\n\", core_id);", + " }", + " *search_terminated |= 8; /* sudden_stop */", + " }", + " if (core_id == 0)", + " { if (((*search_terminated) & 4) /* uerror in one of the cpus */", + " && !((*search_terminated) & (8|32|128|256))) /* abnormal stop */", + " { if (errors == 0) errors++; /* we know there is at least 1 */", + " }", + " wrapup(); /* incomplete stats, but at least something */", + " }", + " return;", + " } /* else: should rarely happen, take more drastic measures */", + "", + " if (core_id == 0) /* local root process */", + " { for (i = 1; i < NCORE; i++) /* not for 0 of course */", + " { int ignore;", + "#if defined(WIN32) || defined(WIN64)", + " DWORD dwExitCode = 0;", + " GetExitCodeProcess(worker_handles[i], &dwExitCode);", + " if (dwExitCode == STILL_ACTIVE)", + " { TerminateProcess(worker_handles[i], 0);", + " }", + " printf(\"cpu0: terminate %%d %%d\\n\",", + " (int) worker_pids[i], (dwExitCode == STILL_ACTIVE));", + "#else", + " sprintf(b, \"kill -%%d %%d\", (int) SIGKILL, (int) worker_pids[i]);", + " ignore = system(b); /* if this is a proxy: receive half */", + " printf(\"cpu0: %%s\\n\", b);", + "#endif", + " }", + " issued_kill++;", + " } else", + " { /* on WIN32/WIN64 -- these merely kills the root process... */", + " if (was_interrupted == 0)", /* 2=SIGINT to root to trigger stop */ + " { int ignore;", + " sprintf(b, \"kill -%%d %%d\", (int) SIGINT, (int) worker_pids[0]);", + " ignore = system(b); /* warn the root process */", + " printf(\"cpu%%d: %%s\\n\", core_id, b);", + " issued_kill++;", + " } }", + "}", + "", + "#define iam_alive() is_alive[core_id]++", /* for crash detection */ + "", + "extern int crash_test(double);", + "extern void crash_reset(void);", + "", + "int", + "someone_crashed(int wait_type)", + "{ static double last_value = 0.0;", + " static int count = 0;", + "", + " if (search_terminated == NULL", + " || *search_terminated != 0)", + " {", + " if (!(*search_terminated & (8|32|128|256)))", + " { if (count++ < 100*NCORE)", + " { return 0;", + " } }", + " return 1;", + " }", + " /* check left neighbor only */", + " if (last_value == is_alive[(core_id + NCORE - 1) %% NCORE])", + " { if (count++ >= 100) /* to avoid unnecessary checks */", + " { return 1;", + " }", + " return 0;", + " }", + " last_value = is_alive[(core_id + NCORE - 1) %% NCORE];", + " count = 0;", + " crash_reset();", + " return 0;", + "}", + "", + "void", + "sleep_report(void)", + "{", + " enter_critical(GLOBAL_LOCK);", + " if (verbose)", + " {", + "#ifdef NGQ", + " printf(\"cpu%%d: locks: global %%g\\tother %%g\\t\",", + " core_id, glock_wait[0], lock_wait - glock_wait[0]);", + "#else", + " printf(\"cpu%%d: locks: GL %%g, RQ %%g, WQ %%g, HT %%g\\t\",", + " core_id, glock_wait[0], glock_wait[1], glock_wait[2],", + " lock_wait - glock_wait[0] - glock_wait[1] - glock_wait[2]);", + "#endif", + " printf(\"waits: states %%g slots %%g\\n\", frame_wait, free_wait);", + "#ifndef NGQ", + " printf(\"cpu%%d: gq [tries %%g, room %%g, noroom %%g]\\n\", core_id, gq_tries, gq_hasroom, gq_hasnoroom);", + " if (core_id == 0 && (*gr_readmiss >= 1.0 || *gr_readmiss >= 1.0 || *grcnt != 0))", + " printf(\"cpu0: gq [readmiss: %%g, writemiss: %%g cnt %%d]\\n\", *gr_readmiss, *gr_writemiss, *grcnt);", + "#endif", + " }", + " if (free_wait > 1000000.)", + " #ifndef NGQ", + " if (!a_cycles)", + " { printf(\"hint: this search may be faster with a larger work-queue\\n\");", + " printf(\" (-DSET_WQ_SIZE=N with N>%%g), and/or with -DUSE_DISK\\n\",", + " GWQ_SIZE/sizeof(SM_frame));", + " printf(\" or with a larger value for -zN (N>%%ld)\\n\", z_handoff);", + " #else", + " { printf(\"hint: this search may be faster if compiled without -DNGQ, with -DUSE_DISK, \");", + " printf(\"or with a larger -zN (N>%%d)\\n\", z_handoff);", + " #endif", + " }", + " leave_critical(GLOBAL_LOCK);", + "}", + "", + "#ifndef MAX_DSK_FILE", + " #define MAX_DSK_FILE 1000000 /* default is max 1M states per file */", + "#endif", + "", + "void", + "multi_usage(FILE *fd)", + "{ static int warned = 0;", + " if (warned > 0) { return; } else { warned++; }", + " fprintf(fd, \"\\n\");", + " fprintf(fd, \"Defining multi-core mode:\\n\\n\");", + " fprintf(fd, \" -DDUAL_CORE --> same as -DNCORE=2\\n\");", + " fprintf(fd, \" -DQUAD_CORE --> same as -DNCORE=4\\n\");", + " fprintf(fd, \" -DNCORE=N --> enables multi_core verification if N>1\\n\");", + " fprintf(fd, \"\\n\");", + " fprintf(fd, \"Additional directives supported in multi-core mode:\\n\\n\");", + " fprintf(fd, \" -DSEP_STATE --> forces separate statespaces instead of a single shared state space\\n\");", + " fprintf(fd, \" -DNUSE_DISK --> use disk for storing states when a work queue overflows\\n\");", + " fprintf(fd, \" -DMAX_DSK_FILE --> max nr of states per diskfile (%%d)\\n\", MAX_DSK_FILE);", + " fprintf(fd, \" -DFULL_TRAIL --> support full error trails (increases memory use)\\n\");", + " fprintf(fd, \"\\n\");", + " fprintf(fd, \"More advanced use (should rarely need changing):\\n\\n\");", + " fprintf(fd, \" To change the nr of states that can be stored in the global queue\\n\");", + " fprintf(fd, \" (lower numbers allow for more states to be stored, prefer multiples of 8):\\n\");", + " fprintf(fd, \" -DVMAX=N --> upperbound on statevector for handoffs (N=%%d)\\n\", VMAX);", + " fprintf(fd, \" -DPMAX=N --> upperbound on nr of procs (default: N=%%d)\\n\", PMAX);", + " fprintf(fd, \" -DQMAX=N --> upperbound on nr of channels (default: N=%%d)\\n\", QMAX);", + " fprintf(fd, \"\\n\");", +#if 0 + "#if !defined(WIN32) && !defined(WIN64)", + " fprintf(fd, \" To change the size of spin's individual shared memory segments for cygwin/linux:\\n\");", + " fprintf(fd, \" -DSET_SEG_SIZE=N --> default %%g (Mbytes)\\n\", SEG_SIZE/(1048576.));", + " fprintf(fd, \"\\n\");", + "#endif", +#endif + " fprintf(fd, \" To set the total amount of memory reserved for the global workqueue:\\n\");", + " fprintf(fd, \" -DSET_WQ_SIZE=N --> default: N=128 (defined in MBytes)\\n\\n\");", +#if 0 + " fprintf(fd, \" To omit the global workqueue completely (bad idea):\\n\");", + " fprintf(fd, \" -DNGQ\\n\\n\");", +#endif + " fprintf(fd, \" To force the use of a single global heap, instead of separate heaps:\\n\");", + " fprintf(fd, \" -DGLOB_HEAP\\n\");", + " fprintf(fd, \"\\n\");", + " fprintf(fd, \" To define a fct to initialize data before spawning processes (use quotes):\\n\");", + " fprintf(fd, \" \\\"-DC_INIT=fct()\\\"\\n\");", + " fprintf(fd, \"\\n\");", + " fprintf(fd, \" Timer settings for termination and crash detection:\\n\");", + " fprintf(fd, \" -DSHORT_T=N --> timeout for termination detection trigger (N=%%g)\\n\", (double) SHORT_T);", + " fprintf(fd, \" -DLONG_T=N --> timeout for giving up on termination detection (N=%%g)\\n\", (double) LONG_T);", + " fprintf(fd, \" -DONESECOND --> (1<<29) --> timeout waiting for a free slot -- to check for crash\\n\");", + " fprintf(fd, \" -DT_ALERT --> collect stats on crash alert timeouts\\n\\n\");", + " fprintf(fd, \"Help with Linux/Windows/Cygwin configuration for multi-core:\\n\");", + " fprintf(fd, \" http://spinroot.com/spin/multicore/V5_Readme.html\\n\");", + " fprintf(fd, \"\\n\");", + "}", + "#if NCORE>1 && defined(FULL_TRAIL)", + "typedef struct Stack_Tree {", + " uchar pr; /* process that made transition */", + " T_ID t_id; /* id of transition */", + " volatile struct Stack_Tree *prv; /* backward link towards root */", + "} Stack_Tree;", + "", + "H_el *grab_shared(int);", + "volatile Stack_Tree **stack_last; /* in shared memory */", + "char *stack_cache = NULL; /* local */", + "int nr_cached = 0; /* local */", + "", + "#ifndef CACHE_NR", + " #define CACHE_NR 1024", + "#endif", + "", + "volatile Stack_Tree *", + "stack_prefetch(void)", + "{ volatile Stack_Tree *st;", + "", + " if (nr_cached == 0)", + " { stack_cache = (char *) grab_shared(CACHE_NR * sizeof(Stack_Tree));", + " nr_cached = CACHE_NR;", + " }", + " st = (volatile Stack_Tree *) stack_cache;", + " stack_cache += sizeof(Stack_Tree);", + " nr_cached--;", + " return st;", + "}", + "", + "void", + "Push_Stack_Tree(short II, T_ID t_id)", + "{ volatile Stack_Tree *st;", + "", + " st = (volatile Stack_Tree *) stack_prefetch();", + " st->pr = II;", + " st->t_id = t_id;", + " st->prv = (Stack_Tree *) stack_last[core_id];", + " stack_last[core_id] = st;", + "}", + "", + "void", + "Pop_Stack_Tree(void)", + "{ volatile Stack_Tree *cf = stack_last[core_id];", + "", + " if (cf)", + " { stack_last[core_id] = cf->prv;", + " } else if (nr_handoffs * z_handoff + depth > 0)", + " { printf(\"cpu%%d: error pop_stack_tree (depth %%ld)\\n\",", + " core_id, depth);", + " }", + "}", + "#endif", /* NCORE>1 && FULL_TRAIL */ + "", + "void", + "e_critical(int which)", + "{ double cnt_start;", + "", + " if (readtrail || iamin[which] > 0)", + " { if (!readtrail && verbose)", + " { printf(\"cpu%%d: Double Lock on %%d (now %%d)\\n\",", + " core_id, which, iamin[which]+1);", + " fflush(stdout);", + " }", + " iamin[which]++; /* local variable */", + " return;", + " }", + "", + " cnt_start = lock_wait;", + "", + " while (sh_lock != NULL) /* as long as we have shared memory */", + " { int r = tas(&sh_lock[which]);", + " if (r == 0)", + " { iamin[which] = 1;", + " return; /* locked */", + " }", + "", + " lock_wait++;", + "#ifndef NGQ", + " if (which < 3) { glock_wait[which]++; }", + "#else", + " if (which == 0) { glock_wait[which]++; }", + "#endif", + " iam_alive();", + "", + " if (lock_wait - cnt_start > TenSeconds)", + " { printf(\"cpu%%d: lock timeout on %%d\\n\", core_id, which);", + " cnt_start = lock_wait;", + " if (someone_crashed(1))", + " { sudden_stop(\"lock timeout\");", + " pan_exit(1);", + " } } }", + "}", + "", + "void", + "x_critical(int which)", + "{", + " if (iamin[which] != 1)", + " { if (iamin[which] > 1)", + " { iamin[which]--; /* this is thread-local - no races on this one */", + " if (!readtrail && verbose)", + " { printf(\"cpu%%d: Partial Unlock on %%d (%%d more needed)\\n\",", + " core_id, which, iamin[which]);", + " fflush(stdout);", + " }", + " return;", + " } else /* iamin[which] <= 0 */", + " { if (!readtrail)", + " { printf(\"cpu%%d: Invalid Unlock iamin[%%d] = %%d\\n\",", + " core_id, which, iamin[which]);", + " fflush(stdout);", + " }", + " return;", + " } }", + "", + " if (sh_lock != NULL)", + " { iamin[which] = 0;", + "#if defined(__powerpc64__)", + " #if 1", + " __sync_synchronize(); /* srirajpaul */", + " #else", + " __lwsync(); /* xlc compiler only */", + " #endif", + "#endif", + " sh_lock[which] = 0; /* unlock */", + " }", + "}", + "", + "void", + "#if defined(WIN32) || defined(WIN64)", + "start_proxy(char *s, DWORD r_pid)", + "#else", + "start_proxy(char *s, int r_pid)", + "#endif", + "{ char Q_arg[16], Z_arg[16], Y_arg[16];", + " char *args[32], *ptr;", + " int argcnt = 0;", + "", + " sprintf(Q_arg, \"-Q%%d\", getpid());", + " sprintf(Y_arg, \"-Y%%d\", r_pid);", + " sprintf(Z_arg, \"-Z%%d\", proxy_pid /* core_id */);", + "", + " args[argcnt++] = \"proxy\";", + " args[argcnt++] = s; /* -r or -s */", + " args[argcnt++] = Q_arg;", + " args[argcnt++] = Z_arg;", + " args[argcnt++] = Y_arg;", + "", + " if (strlen(o_cmdline) > 0)", + " { ptr = o_cmdline; /* assume args separated by spaces */", + " do { args[argcnt++] = ptr++;", + " if ((ptr = strchr(ptr, ' ')) != NULL)", + " { while (*ptr == ' ')", + " { *ptr++ = '\\0';", + " }", + " } else", + " { break;", + " }", + " } while (argcnt < 31);", + " }", + " args[argcnt] = NULL;", + "#if defined(WIN32) || defined(WIN64)", + " execvp(\"pan_proxy\", args); /* no return */", + "#else", + " execvp(\"./pan_proxy\", args); /* no return */", + "#endif", + " Uerror(\"pan_proxy exec failed\");", + "}", + "/*** end of common code fragment ***/", + "", + "#if !defined(WIN32) && !defined(WIN64)", + "void", + "init_shm(void) /* initialize shared work-queues - linux/cygwin */", + "{ key_t key[NR_QS];", + " int n, m;", + " int must_exit = 0;", + "", + " if (core_id == 0 && verbose)", + " { printf(\"cpu0: step 3: allocate shared workqueues %%g MB\\n\",", + " ((double) NCORE * LWQ_SIZE + GWQ_SIZE) / (1048576.) );", + " }", + " for (m = 0; m < NR_QS; m++) /* last q is the global q */", + " { double qsize = (m == NCORE) ? GWQ_SIZE : LWQ_SIZE;", + " key[m] = ftok(PanSource, m+1);", /* m must be nonzero, 1..NCORE */ + " if (key[m] == -1)", + " { perror(\"ftok shared queues\"); must_exit = 1; break;", + " }", + "", + " if (core_id == 0) /* root creates */", + " { /* check for stale copy */", + " shmid[m] = shmget(key[m], (size_t) qsize, 0600);", + " if (shmid[m] != -1) /* yes there is one; remove it */", + " { printf(\"cpu0: removing stale q%%d, status: %%d\\n\",", + " m, shmctl(shmid[m], IPC_RMID, NULL));", + " }", + " shmid[m] = shmget(key[m], (size_t) qsize, 0600|IPC_CREAT|IPC_EXCL);", + " memcnt += qsize;", + " } else /* workers attach */", + " { shmid[m] = shmget(key[m], (size_t) qsize, 0600);", + " /* never called, since we create shm *before* we fork */", + " }", + " if (shmid[m] == -1)", + " { perror(\"shmget shared queues\"); must_exit = 1; break;", + " }", + "", + " shared_mem[m] = (char *) shmat(shmid[m], (void *) 0, 0); /* attach */", + " if (shared_mem[m] == (char *) -1)", + " { fprintf(stderr, \"error: cannot attach shared wq %%d (%%d Mb)\\n\",", + " m+1, (int) (qsize/(1048576.)));", + " perror(\"shmat shared queues\"); must_exit = 1; break;", + " }", + "", + " m_workq[m] = (SM_frame *) shared_mem[m];", + " if (core_id == 0)", + " { int nframes = (m == NCORE) ? GN_FRAMES : LN_FRAMES;", + " for (n = 0; n < nframes; n++)", + " { m_workq[m][n].m_vsize = 0;", + " m_workq[m][n].m_boq = 0;", + " } } }", + "", + " if (must_exit)", + " { rm_shared_segments();", + " fprintf(stderr, \"pan: check './pan --' for usage details\\n\");", + " pan_exit(1); /* calls cleanup_shm */", + " }", + "}", + "", + "static uchar *", + "prep_shmid_S(size_t n) /* either sets SS or H_tab, linux/cygwin */", + "{ char *rval;", + "#ifndef SEP_STATE", + " key_t key;", + "", + " if (verbose && core_id == 0)", + " {", + " #ifdef BITSTATE", + " printf(\"cpu0: step 1: allocate shared bitstate %%g Mb\\n\",", + " (double) n / (1048576.));", + " #else", + " printf(\"cpu0: step 1: allocate shared hastable %%g Mb\\n\",", + " (double) n / (1048576.));", + " #endif", + " }", + " #ifdef MEMLIM", /* memlim has a value */ + " if (memcnt + (double) n > memlim)", + " { printf(\"cpu0: S %%8g + %%d Kb exceeds memory limit of %%8g Mb\\n\",", + " memcnt/1024., (int) (n/1024), memlim/(1048576.));", + " printf(\"cpu0: insufficient memory -- aborting\\n\");", + " exit(1);", + " }", + " #endif", + "", + " key = ftok(PanSource, NCORE+2); /* different from queues */", + " if (key == -1)", + " { perror(\"ftok shared bitstate or hashtable\");", + " fprintf(stderr, \"pan: check './pan --' for usage details\\n\");", + " pan_exit(1);", + " }", + "", + " if (core_id == 0) /* root */", + " { shmid_S = shmget(key, n, 0600);", + " if (shmid_S != -1)", + " { printf(\"cpu0: removing stale segment, status: %%d\\n\",", + " (int) shmctl(shmid_S, IPC_RMID, NULL));", + " }", + " shmid_S = shmget(key, n, 0600 | IPC_CREAT | IPC_EXCL);", + " memcnt += (double) n;", + " } else /* worker */", + " { shmid_S = shmget(key, n, 0600);", + " }", + " if (shmid_S == -1)", + " { perror(\"shmget shared bitstate or hashtable too large?\");", + " fprintf(stderr, \"pan: check './pan --' for usage details\\n\");", + " pan_exit(1);", + " }", + "", + " rval = (char *) shmat(shmid_S, (void *) 0, 0); /* attach */", + " if ((char *) rval == (char *) -1)", + " { perror(\"shmat shared bitstate or hashtable\");", + " fprintf(stderr, \"pan: check './pan --' for usage details\\n\");", + " pan_exit(1);", + " }", + "#else", + " rval = (char *) emalloc(n);", + "#endif", + " return (uchar *) rval;", + "}", + "", + "#define TRY_AGAIN 1", + "#define NOT_AGAIN 0", + "", + "static char shm_prep_result;", + "", + "static uchar *", + "prep_state_mem(size_t n) /* sets memory arena for states linux/cygwin */", + "{ char *rval;", + " key_t key;", + " static int cnt = 3; /* start larger than earlier ftok calls */", + "", + " shm_prep_result = NOT_AGAIN; /* default */", + " if (verbose && core_id == 0)", + " { printf(\"cpu0: step 2+: pre-allocate memory arena %%d of %%6.2g Mb\\n\",", + " cnt-3, (double) n / (1048576.));", + " }", + " #ifdef MEMLIM", + " if (memcnt + (double) n > memlim)", + " { printf(\"cpu0: error: M %%.0f + %%.0f Kb exceeds memory limit of %%.0f Mb\\n\",", + " memcnt/1024.0, (double) n/1024.0, memlim/(1048576.));", + " return NULL;", + " }", + " #endif", + "", + " key = ftok(PanSource, NCORE+cnt); cnt++;", /* starts at NCORE+3 */ + " if (key == -1)", + " { perror(\"ftok T\");", + " printf(\"pan: check './pan --' for usage details\\n\");", + " pan_exit(1);", + " }", + "", + " if (core_id == 0)", + " { shmid_M = shmget(key, n, 0600);", + " if (shmid_M != -1)", + " { printf(\"cpu0: removing stale memory segment %%d, status: %%d\\n\",", + " cnt-3, shmctl(shmid_M, IPC_RMID, NULL));", + " }", + " shmid_M = shmget(key, n, 0600 | IPC_CREAT | IPC_EXCL);", + " /* memcnt += (double) n; -- only amount actually used is counted */", + " } else", + " { shmid_M = shmget(key, n, 0600);", + " ", + " }", + " if (shmid_M == -1)", + " { if (verbose)", + " { printf(\"error: failed to get pool of shared memory %%d of %%.0f Mb\\n\",", + " cnt-3, ((double)n)/(1048576.));", + " perror(\"state mem\");", + " printf(\"pan: check './pan --' for usage details\\n\");", + " }", + " shm_prep_result = TRY_AGAIN;", + " return NULL;", + " }", + " rval = (char *) shmat(shmid_M, (void *) 0, 0); /* attach */", + "", + " if ((char *) rval == (char *) -1)", + " { printf(\"cpu%%d error: failed to attach pool of shared memory %%d of %%.0f Mb\\n\",", + " core_id, cnt-3, ((double)n)/(1048576.));", + " perror(\"state mem\");", + " return NULL;", + " }", + " return (uchar *) rval;", + "}", + "", + "void", + "init_HT(unsigned long n) /* cygwin/linux version */", + "{ volatile char *x;", + " double get_mem;", + "#ifndef SEP_STATE", + " volatile char *dc_mem_start;", + " double need_mem, got_mem = 0.;", + "#endif", + "", +"#ifdef SEP_STATE", + " #ifndef MEMLIM", + " if (verbose)", + " { printf(\"cpu0: steps 0,1: no -DMEMLIM set\\n\");", /* cannot happen */ + " }", + " #else", + " if (verbose)", + " { printf(\"cpu0: steps 0,1: -DMEMLIM=%%d Mb - (hashtable %%g Mb + workqueues %%g Mb)\\n\",", + " MEMLIM, ((double)n/(1048576.)), (((double) NCORE * LWQ_SIZE) + GWQ_SIZE) /(1048576.) );", + " }", + " #endif", + " get_mem = NCORE * sizeof(double) + (1 + CS_NR) * sizeof(void *) + 4*sizeof(void *) + 2*sizeof(double);", + " /* NCORE * is_alive + search_terminated + CS_NR * sh_lock + 6 gr vars */", + " get_mem += 4 * NCORE * sizeof(void *); /* prfree, prfull, prcnt, prmax */", + " #ifdef FULL_TRAIL", + " get_mem += (NCORE) * sizeof(Stack_Tree *); /* NCORE * stack_last */", + " #endif", + " x = (volatile char *) prep_state_mem((size_t) get_mem); /* work queues and basic structs */", + " shmid_X = (long) x;", + " if (x == NULL)", /* do not repeat for smaller sizes */ + " { printf(\"cpu0: could not allocate shared memory, see ./pan --\\n\");", + " exit(1);", + " }", + " search_terminated = (volatile unsigned int *) x; /* comes first */", + " x += sizeof(void *); /* maintain alignment */", + "", + " is_alive = (volatile double *) x;", + " x += NCORE * sizeof(double);", + "", + " sh_lock = (volatile int *) x;", + " x += CS_NR * sizeof(void *);", /* allow 1 word per entry */ + "", + " grfree = (volatile int *) x;", + " x += sizeof(void *);", + " grfull = (volatile int *) x;", + " x += sizeof(void *);", + " grcnt = (volatile int *) x;", + " x += sizeof(void *);", + " grmax = (volatile int *) x;", + " x += sizeof(void *);", + " prfree = (volatile int *) x;", + " x += NCORE * sizeof(void *);", + " prfull = (volatile int *) x;", + " x += NCORE * sizeof(void *);", + " prcnt = (volatile int *) x;", + " x += NCORE * sizeof(void *);", + " prmax = (volatile int *) x;", + " x += NCORE * sizeof(void *);", + " gr_readmiss = (volatile double *) x;", + " x += sizeof(double);", + " gr_writemiss = (volatile double *) x;", + " x += sizeof(double);", + "", + " #ifdef FULL_TRAIL", + " stack_last = (volatile Stack_Tree **) x;", + " x += NCORE * sizeof(Stack_Tree *);", + " #endif", + "", + " #ifndef BITSTATE", + " H_tab = (H_el **) emalloc(n);", + " #endif", +"#else", + " #ifndef MEMLIM", + " #warning MEMLIM not set", /* cannot happen */ + " #define MEMLIM (2048)", + " #endif", + "", + " if (core_id == 0 && verbose)", + " { printf(\"cpu0: step 0: -DMEMLIM=%%d Mb minus hashtable+workqs (%%g + %%g Mb) leaves %%g Mb\\n\",", + " MEMLIM, ((double)n/(1048576.)), (NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.),", + " (memlim - memcnt - (double) n - (NCORE * LWQ_SIZE + GWQ_SIZE))/(1048576.));", + " }", + " #ifndef BITSTATE", + " H_tab = (H_el **) prep_shmid_S((size_t) n); /* hash_table */", + " #endif", + " need_mem = memlim - memcnt - ((double) NCORE * LWQ_SIZE) - GWQ_SIZE;", + " if (need_mem <= 0.)", + " { Uerror(\"internal error -- shared state memory\");", + " }", + "", + " if (core_id == 0 && verbose)", + " { printf(\"cpu0: step 2: pre-allocate shared state memory %%g Mb\\n\",", + " need_mem/(1048576.));", + " }", + "#ifdef SEP_HEAP", + " SEG_SIZE = need_mem / NCORE;", + " if (verbose && core_id == 0)", + " { printf(\"cpu0: setting segsize to %%6g MB\\n\",", + " SEG_SIZE/(1048576.));", + " }", + " #if defined(CYGWIN) || defined(__CYGWIN__)", + " if (SEG_SIZE > 512.*1024.*1024.)", + " { printf(\"warning: reducing SEG_SIZE of %%g MB to 512MB (exceeds max for Cygwin)\\n\",", + " SEG_SIZE/(1024.*1024.));", + " SEG_SIZE = 512.*1024.*1024.;", + " }", + " #endif", + "#endif", + " mem_reserved = need_mem;", + " while (need_mem > 1024.)", + " { get_mem = need_mem;", + "shm_more:", + " if (get_mem > (double) SEG_SIZE)", + " { get_mem = (double) SEG_SIZE;", + " }", + " if (get_mem <= 0.0) break;", + "", + " /* for allocating states: */", + " x = dc_mem_start = (volatile char *) prep_state_mem((size_t) get_mem);", + " if (x == NULL)", + " { if (shm_prep_result == NOT_AGAIN", + " || first_pool != NULL", + " || SEG_SIZE < (16. * 1048576.))", + " { break;", + " }", + " SEG_SIZE /= 2.;", + " if (verbose)", + " { printf(\"pan: lowered segsize to %%f\\n\", SEG_SIZE);", + " }", + " if (SEG_SIZE >= 1024.)", + " { goto shm_more;", /* always terminates */ + " }", + " break;", + " }", + "", + " need_mem -= get_mem;", + " got_mem += get_mem;", + " if (first_pool == NULL)", + " { search_terminated = (volatile unsigned int *) x; /* comes first */", + " x += sizeof(void *); /* maintain alignment */", + "", + " is_alive = (volatile double *) x;", + " x += NCORE * sizeof(double);", + "", + " sh_lock = (volatile int *) x;", + " x += CS_NR * sizeof(void *);", /* allow 1 word per entry */ + "", + " grfree = (volatile int *) x;", + " x += sizeof(void *);", + " grfull = (volatile int *) x;", + " x += sizeof(void *);", + " grcnt = (volatile int *) x;", + " x += sizeof(void *);", + " grmax = (volatile int *) x;", + " x += sizeof(void *);", + " prfree = (volatile int *) x;", + " x += NCORE * sizeof(void *);", + " prfull = (volatile int *) x;", + " x += NCORE * sizeof(void *);", + " prcnt = (volatile int *) x;", + " x += NCORE * sizeof(void *);", + " prmax = (volatile int *) x;", + " x += NCORE * sizeof(void *);", + " gr_readmiss = (volatile double *) x;", + " x += sizeof(double);", + " gr_writemiss = (volatile double *) x;", + " x += sizeof(double);", + " #ifdef FULL_TRAIL", + " stack_last = (volatile Stack_Tree **) x;", + " x += NCORE * sizeof(Stack_Tree *);", + " #endif", + " if (((long)x)&(sizeof(void *)-1)) /* 64-bit word alignment */", + " { x += sizeof(void *)-(((long)x)&(sizeof(void *)-1));", + " }", + "", + " #ifdef COLLAPSE", + " ncomps = (unsigned long *) x;", + " x += (256+2) * sizeof(unsigned long);", + " #endif", + " }", + "", + " dc_shared = (sh_Allocater *) x; /* must be in shared memory */", + " x += sizeof(sh_Allocater);", + "", + " if (core_id == 0) /* root only */", + " { dc_shared->dc_id = shmid_M;", + " dc_shared->dc_start = dc_mem_start;", + " dc_shared->dc_arena = x;", + " dc_shared->pattern = 1234567; /* protection */", + " dc_shared->dc_size = (long) get_mem - (long) (x - dc_mem_start);", + " dc_shared->nxt = (long) 0;", + "", + " if (last_pool == NULL)", + " { first_pool = last_pool = dc_shared;", + " } else", + " { last_pool->nxt = dc_shared;", + " last_pool = dc_shared;", + " }", + " } else if (first_pool == NULL)", + " { first_pool = dc_shared;", + " } }", + "", + " if (need_mem > 1024.)", + " { printf(\"cpu0: could allocate only %%g Mb of shared memory (wanted %%g more)\\n\",", + " got_mem/(1048576.), need_mem/(1048576.));", + " }", + "", + " if (!first_pool)", + " { printf(\"cpu0: insufficient memory -- aborting.\\n\");", + " exit(1);", + " }", + " /* we are still single-threaded at this point, with core_id 0 */", + " dc_shared = first_pool;", + "", +"#endif", /* !SEP_STATE */ + "}", + "", + "void", + "cleanup_shm(int val)", + "{ volatile sh_Allocater *nxt_pool;", + " unsigned long cnt = 0;", + " int m;", + "", + " if (nibis != 0)", + " { printf(\"cpu%%d: Redundant call to cleanup_shm(%%d)\\n\", core_id, val);", + " return;", + " } else", + " { nibis = 1;", + " }", + " if (search_terminated != NULL)", + " { *search_terminated |= 16; /* cleanup_shm */", + " }", + "", + " for (m = 0; m < NR_QS; m++)", + " { if (shmdt((void *) shared_mem[m]) > 0)", + " { perror(\"shmdt detaching from shared queues\");", + " } }", + "", + "#ifdef SEP_STATE", + " if (shmdt((void *) shmid_X) != 0)", + " { perror(\"shmdt detaching from shared state memory\");", + " }", + "#else", + " #ifdef BITSTATE", + " if (SS > 0 && shmdt((void *) SS) != 0)", + " { if (verbose)", + " { perror(\"shmdt detaching from shared bitstate arena\");", + " } }", + " #else", + " if (core_id == 0)", + " { /* before detaching: */", + " for (nxt_pool = dc_shared; nxt_pool != NULL; nxt_pool = nxt_pool->nxt)", + " { cnt += nxt_pool->dc_size;", + " }", + " if (verbose)", + " { printf(\"cpu0: done, %%ld Mb of shared state memory left\\n\",", + " cnt / (long)(1048576));", + " } }", + "", + " if (shmdt((void *) H_tab) != 0)", + " { perror(\"shmdt detaching from shared hashtable\");", + " }", + "", + " for (last_pool = first_pool; last_pool != NULL; last_pool = nxt_pool)", + " { nxt_pool = last_pool->nxt;", + " if (shmdt((void *) last_pool->dc_start) != 0)", + " { perror(\"shmdt detaching from shared state memory\");", + " } }", + " first_pool = last_pool = NULL; /* precaution */", + " #endif", + "#endif", + " /* detached from shared memory - so cannot use cpu_printf */", + " if (verbose)", + " { printf(\"cpu%%d: done -- got %%ld states from queue\\n\",", + " core_id, nstates_get);", + " }", + "}", + "", + "extern void give_up(int);", + "extern void Read_Queue(int);", + "", + "void", + "mem_get(void)", + "{ SM_frame *f;", + " int is_parent;", + "", + "#if defined(MA) && !defined(SEP_STATE)", + " #error MA without SEP_STATE is not supported with multi-core", + "#endif", + "#ifdef BFS", + " #error instead of -DNCORE -DBFS use -DBFS_PAR", + "#endif", + "#ifdef SC", + " #error SC is not supported with multi-core", + "#endif", + " init_shm(); /* we are single threaded when this starts */", + "", + " if (core_id == 0 && verbose)", + " { printf(\"cpu0: step 4: calling fork()\\n\");", + " }", + " fflush(stdout);", + "", + "/* if NCORE > 1 the child or the parent should fork N-1 more times", + " * the parent is the only process with core_id == 0 and is_parent > 0", + " * the workers have is_parent = 0 and core_id = 1..NCORE-1", + " */", + " if (core_id == 0)", + " { worker_pids[0] = getpid(); /* for completeness */", + " while (++core_id < NCORE) /* first worker sees core_id = 1 */", + " { is_parent = fork();", + " if (is_parent == -1)", + " { Uerror(\"fork failed\");", + " }", + " if (is_parent == 0) /* this is a worker process */", + " { if (proxy_pid == core_id) /* always non-zero */", + " { start_proxy(\"-r\", 0); /* no return */", + " }", + " goto adapt; /* root process continues spawning */", + " }", + " worker_pids[core_id] = is_parent;", + " }", + " /* note that core_id is now NCORE */", + " if (proxy_pid > 0 && proxy_pid < NCORE)", /* add send-half of proxy */ + " { proxy_pid_snd = fork();", + " if (proxy_pid_snd == -1)", + " { Uerror(\"proxy fork failed\");", + " }", + " if (proxy_pid_snd == 0)", + " { start_proxy(\"-s\", worker_pids[proxy_pid]); /* no return */", + " } } /* else continue */", + + " if (is_parent > 0)", + " { core_id = 0; /* reset core_id for root process */", + " }", + " } else /* worker */", + " { static char db0[16]; /* good for up to 10^6 cores */", + " static char db1[16];", + "adapt: tprefix = db0; sprefix = db1;", + " sprintf(tprefix, \"cpu%%d_trail\", core_id);", + " sprintf(sprefix, \"cpu%%d_rst\", core_id);", + " memcnt = 0; /* count only additionally allocated memory */", + " }", + " signal(SIGINT, give_up);", + "", + " if (proxy_pid == 0) /* not in a cluster setup, pan_proxy must attach */", + " { rm_shared_segments(); /* mark all shared segments for removal on exit */", + " }", /* doing it early means less chance of being unable to do this */ + " if (verbose)", + " { cpu_printf(\"starting core_id %%d -- pid %%d\\n\", core_id, getpid());", + " }", + + "#if defined(SEP_HEAP) && !defined(SEP_STATE)", /* set my_heap and adjust dc_shared */ + " { int i;", + " volatile sh_Allocater *ptr;", + " ptr = first_pool;", + " for (i = 0; i < NCORE && ptr != NULL; i++)", + " { if (i == core_id)", + " { my_heap = (char *) ptr->dc_arena;", + " my_size = (long) ptr->dc_size;", + " if (verbose)", + " cpu_printf(\"local heap %%ld MB\\n\", my_size/(1048576));", + " break;", + " }", + " ptr = ptr->nxt; /* local */", + " }", + " if (my_heap == NULL)", + " { printf(\"cpu%%d: no local heap\\n\", core_id);", + " pan_exit(1);", + " } /* else */", + " #if defined(CYGWIN) || defined(__CYGWIN__)", + " ptr = first_pool;", + " for (i = 0; i < NCORE && ptr != NULL; i++)", + " { ptr = ptr->nxt; /* local */", + " }", + " dc_shared = ptr; /* any remainder */", + " #else", + " dc_shared = NULL; /* used all mem for local heaps */", + " #endif", + " }", + "#endif", + + " if (core_id == 0 && !remote_party)", + " { new_state(); /* cpu0 explores root */", + " if (verbose)", + " cpu_printf(\"done with 1st dfs, nstates %%g (put %%d states), read q\\n\",", + " nstates, nstates_put);", + " dfs_phase2 = 1;", + " }", + " Read_Queue(core_id); /* all cores */", + "", + " if (verbose)", + " { cpu_printf(\"put %%6d states into queue -- got %%6d\\n\",", + " nstates_put, nstates_get);", + " }", + " if (proxy_pid != 0)", + " { rm_shared_segments();", + " }", + " done = 1;", + " wrapup();", + " exit(0);", + "}", + "", + "#else", + "int unpack_state(SM_frame *, int);", + "#endif", + "", + "H_el *", + "grab_shared(int n)", + "{", + "#ifndef SEP_STATE", + " char *rval = (char *) 0;", + "", + " if (n == 0)", + " { printf(\"cpu%%d: grab shared zero\\n\", core_id); fflush(stdout);", + " return (H_el *) rval;", + " } else if (n&(sizeof(void *)-1))", + " { n += sizeof(void *)-(n&(sizeof(void *)-1)); /* alignment */", + " }", + "", + "#ifdef SEP_HEAP", + " /* no locking */", + " if (my_heap != NULL && my_size > n)", + " { rval = my_heap;", + " my_heap += n;", + " my_size -= n;", + " goto done;", + " }", + "#endif", + "", + " if (!dc_shared)", + " { sudden_stop(\"pan: out of memory\");", + " }", + "", + " /* another lock is always already in effect when this is called */", + " /* but not always the same lock -- i.e., on different parts of the hashtable */", + " enter_critical(GLOBAL_LOCK); /* this must be independently mutex */", + "#if defined(SEP_HEAP) && !defined(WIN32) && !defined(WIN64)", + " { static int noted = 0;", + " if (!noted)", + " { noted = 1;", + " printf(\"cpu%%d: global heap has %%ld bytes left, needed %%d\\n\",", + " core_id, dc_shared?dc_shared->dc_size:0, n);", + " } }", + "#endif", + "#if 0", /* for debugging */ + " if (dc_shared->pattern != 1234567)", + " { leave_critical(GLOBAL_LOCK);", + " Uerror(\"overrun -- memory corruption\");", + " }", + "#endif", + " if (dc_shared->dc_size < n)", + " { if (verbose)", + " { printf(\"Next Pool %%g Mb + %%d\\n\", memcnt/(1048576.), n);", + " }", + " if (dc_shared->nxt == NULL", + " || dc_shared->nxt->dc_arena == NULL", + " || dc_shared->nxt->dc_size < n)", + " { printf(\"cpu%%d: memcnt %%g Mb + wanted %%d bytes more\\n\",", + " core_id, memcnt / (1048576.), n);", + " leave_critical(GLOBAL_LOCK);", + " sudden_stop(\"out of memory -- aborting\");", + " wrapup(); /* exits */", + " } else", + " { dc_shared = (sh_Allocater *) dc_shared->nxt;", + " } }", + "", + " rval = (char *) dc_shared->dc_arena;", + " dc_shared->dc_arena += n;", + " dc_shared->dc_size -= (long) n;", + "#if 0", + " if (VVERBOSE)", + " printf(\"cpu%%d grab shared (%%d bytes) -- %%ld left\\n\",", + " core_id, n, dc_shared->dc_size);", + "#endif", + " leave_critical(GLOBAL_LOCK);", + "done:", + " memset(rval, 0, n);", + " memcnt += (double) n;", + "", + " return (H_el *) rval;", + "#else", + " return (H_el *) emalloc(n);", + "#endif", + "}", + "", + "SM_frame *", + "Get_Full_Frame(int n)", + "{ SM_frame *f;", + " double cnt_start = frame_wait;", + "", + " f = &m_workq[n][prfull[n]];", + " while (f->m_vsize == 0) /* await full slot LOCK : full frame */", + " { iam_alive();", + "#ifndef NGQ", + " #ifndef SAFETY", + " if (!a_cycles || core_id != 0)", + " #endif", + " if (*grcnt > 0) /* accessed outside lock, but safe even if wrong */", + " { enter_critical(GQ_RD); /* gq - read access */", + " if (*grcnt > 0) /* could have changed */", + " { f = &m_workq[NCORE][*grfull]; /* global q */", + " if (f->m_vsize == 0)", + " { /* writer is still filling the slot */", + " *gr_writemiss++;", + " f = &m_workq[n][prfull[n]]; /* reset */", + " } else", + " { *grfull = (*grfull+1) %% (GN_FRAMES);", + " enter_critical(GQ_WR);", + " *grcnt = *grcnt - 1;", + " leave_critical(GQ_WR);", + " leave_critical(GQ_RD);", + " return f;", + " } }", + " leave_critical(GQ_RD);", + " }", + "#endif", + " if (frame_wait++ - cnt_start > Delay)", + " { if (0)", /* too frequent to enable this one */ + " { cpu_printf(\"timeout on q%%d -- %%u -- query %%d\\n\",", + " n, f, query_in_progress);", + " }", + " return (SM_frame *) 0; /* timeout */", + " } }", + " iam_alive();", + " if (VVERBOSE) cpu_printf(\"got frame from q%%d\\n\", n);", + " prfull[n] = (prfull[n] + 1) %% (LN_FRAMES);", + " enter_critical(QLOCK(n));", + " prcnt[n]--; /* lock out increments */", + " leave_critical(QLOCK(n));", + " return f;", + "}", + "", + "SM_frame *", + "Get_Free_Frame(int n)", + "{ SM_frame *f;", + " double cnt_start = free_wait;", + "", + " if (VVERBOSE) { cpu_printf(\"get free frame from q%%d\\n\", n); }", + "", + " if (n == NCORE) /* global q */", + " { f = &(m_workq[n][lrfree]);", + " } else", + " { f = &(m_workq[n][prfree[n]]);", + " }", + " while (f->m_vsize != 0) /* await free slot LOCK : free slot */", + " { iam_alive();", + " if (free_wait++ - cnt_start > OneSecond)", + " { if (verbose)", + " { cpu_printf(\"timeout waiting for free slot q%%d\\n\", n);", + " }", + " cnt_start = free_wait;", + " if (someone_crashed(1))", + " { printf(\"cpu%%d: search terminated\\n\", core_id);", + " sudden_stop(\"get free frame\");", + " pan_exit(1);", + " } } }", + " if (n != NCORE)", + " { prfree[n] = (prfree[n] + 1) %% (LN_FRAMES);", + " enter_critical(QLOCK(n));", + " prcnt[n]++; /* lock out decrements */", + " if (prmax[n] < prcnt[n])", + " { prmax[n] = prcnt[n];", + " }", + " leave_critical(QLOCK(n));", + " }", + " return f;", + "}", + "", + "#ifndef NGQ", + "int", + "GlobalQ_HasRoom(void)", + "{ int rval = 0;", + "", + " gq_tries++;", + " if (*grcnt < GN_FRAMES) /* there seems to be room */", + " { enter_critical(GQ_WR); /* gq write access */", + " if (*grcnt < GN_FRAMES)", + " { if (m_workq[NCORE][*grfree].m_vsize != 0)", + " { /* can happen if reader is slow emptying slot */", + " *gr_readmiss++;", + " goto out; /* dont wait: release lock and return */", + " }", + " lrfree = *grfree; /* Get_Free_Frame use lrfree in this mode */", + " *grfree = (*grfree + 1) %% GN_FRAMES;", /* next process looks at next slot */ + " *grcnt = *grcnt + 1; /* count nr of slots filled -- no additional lock needed */", + " if (*grmax < *grcnt) *grmax = *grcnt;", + " leave_critical(GQ_WR); /* for short lock duration */", + " gq_hasroom++;", + " mem_put(NCORE); /* copy state into reserved slot */", + " rval = 1; /* successfull handoff */", + " } else", + " { gq_hasnoroom++;", + "out: leave_critical(GQ_WR);", /* should be rare */ + " } }", + " return rval;", + "}", + "#endif", + "", + "int", + "unpack_state(SM_frame *f, int from_q)", + "{ int i, j;", + " static H_el D_State;", + "", + " if (f->m_vsize > 0)", + " { boq = f->m_boq;", + " if (boq > 256)", + " { cpu_printf(\"saw control %%d, expected state\\n\", boq);", + " return 0;", + " }", + " vsize = f->m_vsize;", + "correct:", + " memcpy((uchar *) &now, (uchar *) f->m_now, vsize);", + " #if !defined(NOCOMP) && !defined(HC)", + " for (i = j = 0; i < VMAX; i++, j = (j+1)%%8)", + " { Mask[i] = (f->m_mask[i/8] & (1< 0)", + " { memcpy((uchar *) proc_offset, (uchar *) f->m_p_offset, now._nr_pr * sizeof(OFFT));", + " memcpy((uchar *) proc_skip, (uchar *) f->m_p_skip, now._nr_pr * sizeof(uchar));", + " }", + " if (now._nr_qs > 0)", + " { memcpy((uchar *) q_offset, (uchar *) f->m_q_offset, now._nr_qs * sizeof(OFFT));", + " memcpy((uchar *) q_skip, (uchar *) f->m_q_skip, now._nr_qs * sizeof(uchar));", + " }", + "#ifndef NOVSZ", + " if (vsize != now._vsz)", + " { cpu_printf(\"vsize %%d != now._vsz %%d (type %%d) %%d\\n\",", + " vsize, now._vsz, f->m_boq, f->m_vsize);", + " vsize = now._vsz;", + " goto correct; /* rare event: a race */", + " }", + "#endif", + " hmax = max(hmax, vsize);", + "", + " if (f != &cur_Root)", + " { memcpy((uchar *) &cur_Root, (uchar *) f, sizeof(SM_frame));", + " }", + "", + " if (((now._a_t) & 1) == 1) /* i.e., when starting nested DFS */", + " { A_depth = depthfound = 0;", + " memcpy((uchar *)&A_Root, (uchar *)&now, vsize);", + " }", + " nr_handoffs = f->nr_handoffs;", + " } else", + " { cpu_printf(\"pan: state empty\\n\");", + " }", + "", + " depth = 0;", + " trpt = &trail[1];", + " trpt->tau = f->m_tau;", + " trpt->o_pm = f->m_o_pm;", + "", + " (trpt-1)->ostate = &D_State; /* stub */", + " trpt->ostate = &D_State;", + "", + "#ifdef FULL_TRAIL", + " if (upto > 0)", + " { stack_last[core_id] = (Stack_Tree *) f->m_stack;", + " }", + " #if defined(VERBOSE)", + " if (stack_last[core_id])", + " { cpu_printf(\"%%d: UNPACK -- SET m_stack %%u (%%d,%%d)\\n\",", + " depth, stack_last[core_id], stack_last[core_id]->pr,", + " stack_last[core_id]->t_id);", + " }", + " #endif", + "#endif", + "", + " if (!trpt->o_t)", + " { static Trans D_Trans;", + " trpt->o_t = &D_Trans;", + " }", + "", + " #ifdef VERI", + " if ((trpt->tau & 4) != 4)", + " { trpt->tau |= 4; /* the claim moves first */", + " cpu_printf(\"warning: trpt was not up to date\\n\");", + " }", + " #endif", + "", + " for (i = 0; i < (int) now._nr_pr; i++)", + " { P0 *ptr = (P0 *) pptr(i);", + " #ifndef NP", + " if (accpstate[ptr->_t][ptr->_p])", + " { trpt->o_pm |= 2;", + " }", + " #else", + " if (progstate[ptr->_t][ptr->_p])", + " { trpt->o_pm |= 4;", + " }", + " #endif", + " }", + "", + " #ifdef EVENT_TRACE", + " #ifndef NP", + " if (accpstate[EVENT_TRACE][now._event])", + " { trpt->o_pm |= 2;", + " }", + " #else", + " if (progstate[EVENT_TRACE][now._event])", + " { trpt->o_pm |= 4;", + " }", + " #endif", + " #endif", + "", + " #if defined(C_States) && (HAS_TRACK==1)", + " /* restore state of tracked C objects */", + " c_revert((uchar *) &(now.c_state[0]));", + " #if (HAS_STACK==1)", + " c_unstack((uchar *) f->m_c_stack); /* unmatched tracked data */", + " #endif", + " #endif", + " return 1;", + "}", + "", + "void", + "write_root(void) /* for trail file */", + "{ int fd;", + "", + " if (iterative == 0 && Nr_Trails > 1)", + " sprintf(fnm, \"%%s%%d.%%s\", TrailFile, Nr_Trails-1, sprefix);", + " else", + " sprintf(fnm, \"%%s.%%s\", TrailFile, sprefix);", + "", + " if (cur_Root.m_vsize == 0)", + " { (void) unlink(fnm); /* remove possible old copy */", + " return; /* its the default initial state */", + " }", + "", + " if ((fd = creat(fnm, TMODE)) < 0)", + " { char *q;", + " if ((q = strchr(TrailFile, \'.\')))", + " { *q = \'\\0\'; /* strip .pml */", + " if (iterative == 0 && Nr_Trails-1 > 0)", + " sprintf(fnm, \"%%s%%d.%%s\", TrailFile, Nr_Trails-1, sprefix);", + " else", + " sprintf(fnm, \"%%s.%%s\", TrailFile, sprefix);", + " *q = \'.\';", + " fd = creat(fnm, TMODE);", + " }", + " if (fd < 0)", + " { cpu_printf(\"pan: cannot create %%s\\n\", fnm);", + " perror(\"cause\");", + " return;", + " } }", + "", + " if (write(fd, &cur_Root, sizeof(SM_frame)) != sizeof(SM_frame))", + " { cpu_printf(\"pan: error writing %%s\\n\", fnm);", + " } else", + " { cpu_printf(\"pan: wrote %%s\\n\", fnm);", + " }", + " close(fd);", + "}", + "", + "void", + "set_root(void)", + "{ int fd;", + " char *q;", + " char MyFile[512];", /* enough to hold a reasonable pathname */ + " char MySuffix[16];", + " char *ssuffix = \"rst\";", + " int try_core = 1;", + "", + " strcpy(MyFile, TrailFile);", + "try_again:", + " if (whichtrail > 0)", + " { sprintf(fnm, \"%%s%%d.%%s\", MyFile, whichtrail, ssuffix);", + " fd = open(fnm, O_RDONLY, 0);", + " if (fd < 0 && (q = strchr(MyFile, \'.\')))", + " { *q = \'\\0\'; /* strip .pml */", + " sprintf(fnm, \"%%s%%d.%%s\", MyFile, whichtrail, ssuffix);", + " *q = \'.\';", + " fd = open(fnm, O_RDONLY, 0);", + " }", + " } else", + " { sprintf(fnm, \"%%s.%%s\", MyFile, ssuffix);", + " fd = open(fnm, O_RDONLY, 0);", + " if (fd < 0 && (q = strchr(MyFile, \'.\')))", + " { *q = \'\\0\'; /* strip .pml */", + " sprintf(fnm, \"%%s.%%s\", MyFile, ssuffix);", + " *q = \'.\';", + " fd = open(fnm, O_RDONLY, 0);", + " } }", + "", + " if (fd < 0)", + " { if (try_core < NCORE)", + " { ssuffix = MySuffix;", + " sprintf(ssuffix, \"cpu%%d_rst\", try_core++);", + " goto try_again;", + " }", + " cpu_printf(\"no file '%%s.rst' or '%%s' (not an error)\\n\", MyFile, fnm);", + " } else", + " { if (read(fd, &cur_Root, sizeof(SM_frame)) != sizeof(SM_frame))", + " { cpu_printf(\"read error %%s\\n\", fnm);", + " close(fd);", + " pan_exit(1);", + " }", + " close(fd);", + " (void) unpack_state(&cur_Root, -2);", + "#ifdef SEP_STATE", + " cpu_printf(\"partial trail -- last few steps only\\n\");", + "#endif", + " cpu_printf(\"restored root from '%%s'\\n\", fnm);", + " printf(\"=====State:=====\\n\");", + " { int i, j; P0 *z;", + " for (i = 0; i < now._nr_pr; i++)", + " { z = (P0 *)pptr(i);", + " printf(\"proc %%2d (%%s) \", i, procname[z->_t]);", + + " for (j = 0; src_all[j].src; j++)", + " if (src_all[j].tp == (int) z->_t)", + " { printf(\" %%s:%%d \",", + " PanSource, src_all[j].src[z->_p]);", + " break;", + " }", + " printf(\"(state %%d)\\n\", z->_p);", + " c_locals(i, z->_t);", + " }", + " c_globals();", + " }", + " printf(\"================\\n\");", + " }", + "}", + "", + "#ifdef USE_DISK", + "unsigned long dsk_written, dsk_drained;", + "void mem_drain(void);", + "#endif", + "", + "void", + "m_clear_frame(SM_frame *f)", /* clear room for stats */ + "{ int i, clr_sz = sizeof(SM_results);", + "", + " for (i = 0; i <= _NP_; i++) /* all proctypes */", + " { clr_sz += NrStates[i]*sizeof(uchar);", + " }", + " memset(f, 0, clr_sz);", + " /* caution if sizeof(SM_results) > sizeof(SM_frame) */", + "}", + "", + "#define TargetQ_Full(n) (m_workq[n][prfree[n]].m_vsize != 0)", /* no free slot */ + "#define TargetQ_NotFull(n) (m_workq[n][prfree[n]].m_vsize == 0)", /* avoiding prcnt */ + "", + "int", + "AllQueuesEmpty(void)", + "{ int q;", + "#ifndef NGQ", + " if (*grcnt != 0)", + " { return 0;", + " }", + "#endif", + " for (q = 0; q < NCORE; q++)", + " { if (prcnt[q] != 0)", /* not locked, ok if race */ + " { return 0;", + " } }", + " return 1;", + "}", + "", + "void", + "Read_Queue(int q)", + "{ SM_frame *f, *of;", + " int remember, target_q;", + " SM_results *r;", + " double patience = 0.0;", + "", + " target_q = (q + 1) %% NCORE;", + "", + " for (;;)", + " { f = Get_Full_Frame(q);", + " if (!f) /* 1 second timeout -- and trigger for Query */", + " { if (someone_crashed(2))", + " { printf(\"cpu%%d: search terminated [code %%d]\\n\",", + " core_id, search_terminated?*search_terminated:-1);", + " sudden_stop(\"\");", + " pan_exit(1);", + " }", + "#ifdef TESTING", + " /* to profile with cc -pg and gprof pan.exe -- set handoff depth beyond maxdepth */", + " exit(0);", + "#endif", + " remember = *grfree;", + " if (core_id == 0 /* root can initiate termination */", + " && remote_party == 0 /* and only the original root */", + " && query_in_progress == 0 /* unless its already in progress */", + " && AllQueuesEmpty())", + " { f = Get_Free_Frame(target_q);", + " query_in_progress = 1; /* only root process can do this */", + " if (!f) { Uerror(\"Fatal1: no free slot\"); }", + " f->m_boq = QUERY; /* initiate Query */", + " if (verbose)", + " { cpu_printf(\"snd QUERY to q%%d (%%d) into slot %%d\\n\",", + " target_q, nstates_get + 1, prfree[target_q]-1);", + " }", + " f->m_vsize = remember + 1;", + " /* number will not change unless we receive more states */", + " } else if (patience++ > OneHour) /* one hour watchdog timer */", + " { cpu_printf(\"timeout -- giving up\\n\");", + " sudden_stop(\"queue timeout\");", + " pan_exit(1);", + " }", + " if (0) cpu_printf(\"timed out -- try again\\n\");", + " continue; ", + " }", + " patience = 0.0; /* reset watchdog */", + "", + " if (f->m_boq == QUERY)", + " { if (verbose)", + " { cpu_printf(\"got QUERY on q%%d (%%d <> %%d) from slot %%d\\n\",", + " q, f->m_vsize, nstates_put + 1, prfull[q]-1);", + " snapshot();", + " }", + " remember = f->m_vsize;", + " f->m_vsize = 0; /* release slot */", + "", + " if (core_id == 0 && remote_party == 0) /* original root cpu0 */", + " { if (query_in_progress == 1 /* didn't send more states in the interim */", + " && *grfree + 1 == remember) /* no action on global queue meanwhile */", + " { if (verbose) cpu_printf(\"Termination detected\\n\");", + " if (TargetQ_Full(target_q))", + " { if (verbose)", + " cpu_printf(\"warning: target q is full\\n\");", + " }", + " f = Get_Free_Frame(target_q);", + " if (!f) { Uerror(\"Fatal2: no free slot\"); }", + " m_clear_frame(f);", + " f->m_boq = QUIT; /* send final Quit, collect stats */", + " f->m_vsize = 111; /* anything non-zero will do */", + " if (verbose)", + " cpu_printf(\"put QUIT on q%%d\\n\", target_q);", + " } else", + " { if (verbose) cpu_printf(\"Stale Query\\n\");", + "#ifdef USE_DISK", + " mem_drain();", + "#endif", + " }", + " query_in_progress = 0;", + " } else", + " { if (TargetQ_Full(target_q))", + " { if (verbose)", + " cpu_printf(\"warning: forward query - target q full\\n\");", + " }", + " f = Get_Free_Frame(target_q);", + " if (verbose)", + " cpu_printf(\"snd QUERY response to q%%d (%%d <> %%d) in slot %%d\\n\",", + " target_q, remember, *grfree + 1, prfree[target_q]-1);", + " if (!f) { Uerror(\"Fatal4: no free slot\"); }", + "", + " if (*grfree + 1 == remember) /* no action on global queue */", + " { f->m_boq = QUERY; /* forward query, to root */", + " f->m_vsize = remember;", + " } else", + " { f->m_boq = QUERY_F; /* no match -- busy */", + " f->m_vsize = 112; /* anything non-zero */", + "#ifdef USE_DISK", + " if (dsk_written != dsk_drained)", + " { mem_drain();", + " }", + "#endif", + " } }", + " continue;", + " }", + "", + " if (f->m_boq == QUERY_F)", + " { if (verbose)", + " { cpu_printf(\"got QUERY_F on q%%d from slot %%d\\n\", q, prfull[q]-1);", + " }", + " f->m_vsize = 0; /* release slot */", + "", + " if (core_id == 0 && remote_party == 0) /* original root cpu0 */", + " { if (verbose) cpu_printf(\"No Match on Query\\n\");", + " query_in_progress = 0;", + " } else", + " { if (TargetQ_Full(target_q))", + " { if (verbose) cpu_printf(\"warning: forwarding query_f, target queue full\\n\");", + " }", + " f = Get_Free_Frame(target_q);", + " if (verbose) cpu_printf(\"forward QUERY_F to q%%d into slot %%d\\n\",", + " target_q, prfree[target_q]-1);", + " if (!f) { Uerror(\"Fatal5: no free slot\"); }", + " f->m_boq = QUERY_F; /* cannot terminate yet */", + " f->m_vsize = 113; /* anything non-zero */", + " }", + "#ifdef USE_DISK", + " if (dsk_written != dsk_drained)", + " { mem_drain();", + " }", + "#endif", + " continue;", + " }", + "", + " if (f->m_boq == QUIT)", + " { if (0) cpu_printf(\"done -- local memcnt %%g Mb\\n\", memcnt/(1048576.));", + " retrieve_info((SM_results *) f); /* collect and combine stats */", + " if (verbose)", + " { cpu_printf(\"received Quit\\n\");", + " snapshot();", + " }", + " f->m_vsize = 0; /* release incoming slot */", + " if (core_id != 0)", + " { f = Get_Free_Frame(target_q); /* new outgoing slot */", + " if (!f) { Uerror(\"Fatal6: no free slot\"); }", + " m_clear_frame(f); /* start with zeroed stats */", + " record_info((SM_results *) f);", + " f->m_boq = QUIT; /* forward combined results */", + " f->m_vsize = 114; /* anything non-zero */", + " if (verbose>1)", + " cpu_printf(\"fwd Results to q%%d\\n\", target_q);", + " }", + " break; /* successful termination */", + " }", + "", + " /* else: 0<= boq <= 255, means STATE transfer */", + " if (unpack_state(f, q) != 0)", + " { nstates_get++;", + " f->m_vsize = 0; /* release slot */", + " if (VVERBOSE) cpu_printf(\"Got state\\n\");", + "", + " if (search_terminated != NULL", + " && *search_terminated == 0)", + " { new_state(); /* explore successors */", + " memset((uchar *) &cur_Root, 0, sizeof(SM_frame)); /* avoid confusion */", + " } else", + " { pan_exit(0);", + " }", + " } else", + " { pan_exit(0);", + " } }", + " if (verbose) cpu_printf(\"done got %%d put %%d\\n\", nstates_get, nstates_put);", + " sleep_report();", + "}", + "", + "void", + "give_up(int unused_x)", + "{", + " if (search_terminated != NULL)", + " { *search_terminated |= 32; /* give_up */", + " }", + " if (!writing_trail)", + " { was_interrupted = 1;", + " snapshot();", + " cpu_printf(\"Give Up\\n\");", + " sleep_report();", + " pan_exit(1);", + " } else /* we are already terminating */", + " { cpu_printf(\"SIGINT\\n\");", + " }", + "}", + "", + "void", + "check_overkill(void)", + "{", + " vmax_seen = (vmax_seen + 7)/ 8;", + " vmax_seen *= 8; /* round up to a multiple of 8 */", + "", + " if (core_id == 0", + " && !remote_party", + " && nstates_put > 0", + " && VMAX - vmax_seen > 8)", + " {", + "#ifdef BITSTATE", + " printf(\"cpu0: max VMAX value seen in this run: \");", + "#else", + " printf(\"cpu0: recommend recompiling with \");", + "#endif", + " printf(\"-DVMAX=%%d\\n\", vmax_seen);", + " }", + "}", + "", + "void", + "mem_put(int q) /* handoff state to other cpu, workq q */", + "{ SM_frame *f;", + " int i, j;", + "", + " if (vsize > VMAX)", + " { vsize = (vsize + 7)/8; vsize *= 8; /* round up */", + " printf(\"pan: recompile with -DVMAX=N with N >= %%d\\n\", (int) vsize);", + " Uerror(\"aborting\");", + " }", + " if (now._nr_pr > PMAX)", + " { printf(\"pan: recompile with -DPMAX=N with N >= %%d\\n\", now._nr_pr);", + " Uerror(\"aborting\");", + " }", + " if (now._nr_qs > QMAX)", + " { printf(\"pan: recompile with -DQMAX=N with N >= %%d\\n\", now._nr_qs);", + " Uerror(\"aborting\");", + " }", + " if (vsize > vmax_seen) vmax_seen = vsize;", + " if (now._nr_pr > pmax_seen) pmax_seen = now._nr_pr;", + " if (now._nr_qs > qmax_seen) qmax_seen = now._nr_qs;", + "", + " f = Get_Free_Frame(q); /* not called in likely deadlock states */", + " if (!f) { Uerror(\"Fatal3: no free slot\"); }", + "", + " if (VVERBOSE) cpu_printf(\"putting state into q%%d\\n\", q);", + "", + " memcpy((uchar *) f->m_now, (uchar *) &now, vsize);", + "#if !defined(NOCOMP) && !defined(HC)", + " memset((uchar *) f->m_mask, 0, (VMAX+7)/8 * sizeof(char));", + " for (i = j = 0; i < VMAX; i++, j = (j+1)%%8)", + " { if (Mask[i])", + " { f->m_mask[i/8] |= (1< 0)", + " { memcpy((uchar *) f->m_p_offset, (uchar *) proc_offset, now._nr_pr * sizeof(OFFT));", + " memcpy((uchar *) f->m_p_skip, (uchar *) proc_skip, now._nr_pr * sizeof(uchar));", + " }", + " if (now._nr_qs > 0)", + " { memcpy((uchar *) f->m_q_offset, (uchar *) q_offset, now._nr_qs * sizeof(OFFT));", + " memcpy((uchar *) f->m_q_skip, (uchar *) q_skip, now._nr_qs * sizeof(uchar));", + " }", + "#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)", + " c_stack((uchar *) f->m_c_stack); /* save unmatched tracked data */", + "#endif", + "#ifdef FULL_TRAIL", + " f->m_stack = stack_last[core_id];", + "#endif", + " f->nr_handoffs = nr_handoffs+1;", + " f->m_tau = trpt->tau;", + " f->m_o_pm = trpt->o_pm;", + " f->m_boq = boq;", + " f->m_vsize = vsize; /* must come last - now the other cpu can see it */", + "", + " if (query_in_progress == 1)", + " query_in_progress = 2; /* make sure we know, if a query makes the rounds */", + " nstates_put++;", + "}", + "", + "#ifdef USE_DISK", + "int Dsk_W_Nr, Dsk_R_Nr;", + "int dsk_file = -1, dsk_read = -1;", + "unsigned long dsk_written, dsk_drained;", + "char dsk_name[512];", + "", + "#ifndef BFS_DISK", + "#if defined(WIN32) || defined(WIN64)", + " #define RFLAGS (O_RDONLY|O_BINARY)", + " #define WFLAGS (O_CREAT|O_WRONLY|O_TRUNC|O_BINARY)", + "#else", + " #define RFLAGS (O_RDONLY)", + " #define WFLAGS (O_CREAT|O_WRONLY|O_TRUNC)", + "#endif", + "#endif", + "", + "void", + "dsk_stats(void)", + "{ int i;", + "", + " if (dsk_written > 0)", + " { cpu_printf(\"dsk_written %%d states in %%d files\\ncpu%%d: dsk_drained %%6d states\\n\",", + " dsk_written, Dsk_W_Nr, core_id, dsk_drained);", + " close(dsk_read);", + " close(dsk_file);", + " for (i = 0; i < Dsk_W_Nr; i++)", + " { sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", i, core_id);", + " unlink(dsk_name);", + " } }", + "}", + "", + "void", + "mem_drain(void)", + "{ SM_frame *f, g;", + " int q = (core_id + 1) %% NCORE; /* target q */", + " int sz;", + "", + " if (dsk_read < 0", + " || dsk_written <= dsk_drained)", + " { return;", + " }", + "", + " while (dsk_written > dsk_drained", + " && TargetQ_NotFull(q))", + " { f = Get_Free_Frame(q);", + " if (!f) { Uerror(\"Fatal: unhandled condition\"); }", + "", + " if ((dsk_drained+1)%%MAX_DSK_FILE == 0) /* 100K states max per file */", + " { (void) close(dsk_read); /* close current read handle */", + " sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", Dsk_R_Nr++, core_id);", + " (void) unlink(dsk_name); /* remove current file */", + " sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", Dsk_R_Nr, core_id);", + " cpu_printf(\"reading %%s\\n\", dsk_name);", + " dsk_read = open(dsk_name, RFLAGS); /* open next file */", + " if (dsk_read < 0)", + " { Uerror(\"could not open dsk file\");", + " } }", + " if (read(dsk_read, &g, sizeof(SM_frame)) != sizeof(SM_frame))", + " { Uerror(\"bad dsk file read\");", + " }", + " sz = g.m_vsize;", + " g.m_vsize = 0;", + " memcpy(f, &g, sizeof(SM_frame));", + " f->m_vsize = sz; /* last */", + "", + " dsk_drained++;", + " }", + "}", + "", + "void", + "mem_file(void)", + "{ SM_frame f;", + " int i, j, q = (core_id + 1) %% NCORE; /* target q */", + "", + " if (vsize > VMAX)", + " { printf(\"pan: recompile with -DVMAX=N with N >= %%d\\n\", vsize);", + " Uerror(\"aborting\");", + " }", + " if (now._nr_pr > PMAX)", + " { printf(\"pan: recompile with -DPMAX=N with N >= %%d\\n\", now._nr_pr);", + " Uerror(\"aborting\");", + " }", + " if (now._nr_qs > QMAX)", + " { printf(\"pan: recompile with -DQMAX=N with N >= %%d\\n\", now._nr_qs);", + " Uerror(\"aborting\");", + " }", + "", + " if (VVERBOSE) cpu_printf(\"filing state for q%%d\\n\", q);", + "", + " memcpy((uchar *) f.m_now, (uchar *) &now, vsize);", + "#if !defined(NOCOMP) && !defined(HC)", + " memset((uchar *) f.m_mask, 0, (VMAX+7)/8 * sizeof(char));", + " for (i = j = 0; i < VMAX; i++, j = (j+1)%%8)", + " { if (Mask[i])", + " { f.m_mask[i/8] |= (1< 0)", + " { memcpy((uchar *)f.m_p_offset, (uchar *)proc_offset, now._nr_pr*sizeof(OFFT));", + " memcpy((uchar *)f.m_p_skip, (uchar *)proc_skip, now._nr_pr*sizeof(uchar));", + " }", + " if (now._nr_qs > 0)", + " { memcpy((uchar *) f.m_q_offset, (uchar *) q_offset, now._nr_qs*sizeof(OFFT));", + " memcpy((uchar *) f.m_q_skip, (uchar *) q_skip, now._nr_qs*sizeof(uchar));", + " }", + "#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)", + " c_stack((uchar *) f.m_c_stack); /* save unmatched tracked data */", + "#endif", + "#ifdef FULL_TRAIL", + " f.m_stack = stack_last[core_id];", + "#endif", + " f.nr_handoffs = nr_handoffs+1;", + " f.m_tau = trpt->tau;", + " f.m_o_pm = trpt->o_pm;", + " f.m_boq = boq;", + " f.m_vsize = vsize;", + "", + " if (query_in_progress == 1)", + " { query_in_progress = 2;", + " }", + " if (dsk_file < 0)", + " { sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", Dsk_W_Nr, core_id);", + " dsk_file = open(dsk_name, WFLAGS, 0644);", + " dsk_read = open(dsk_name, RFLAGS);", + " if (dsk_file < 0 || dsk_read < 0)", + " { cpu_printf(\"File: <%%s>\\n\", dsk_name);", + " Uerror(\"cannot open diskfile\");", + " }", + " Dsk_W_Nr++; /* nr of next file to open */", + " cpu_printf(\"created temporary diskfile %%s\\n\", dsk_name);", + " } else if ((dsk_written+1)%%MAX_DSK_FILE == 0)", + " { close(dsk_file); /* close write handle */", + " sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", Dsk_W_Nr++, core_id);", + " dsk_file = open(dsk_name, WFLAGS, 0644);", + " if (dsk_file < 0)", + " { cpu_printf(\"File: <%%s>\\n\", dsk_name);", + " Uerror(\"aborting: cannot open new diskfile\");", + " }", + " cpu_printf(\"created temporary diskfile %%s\\n\", dsk_name);", + " }", + " if (write(dsk_file, &f, sizeof(SM_frame)) != sizeof(SM_frame))", + " { Uerror(\"aborting -- disk write failed (disk full?)\");", + " }", + " nstates_put++;", + " dsk_written++;", + "}", + "#endif", + "", + "int", + "mem_hand_off(void)", + "{", + " if (search_terminated == NULL", + " || *search_terminated != 0) /* not a full crash check */", + " { pan_exit(0);", + " }", + " iam_alive(); /* on every transition of Down */", + "#ifdef USE_DISK", + " mem_drain(); /* maybe call this also on every Up */", + "#endif", + " if (depth > z_handoff /* above handoff limit */", + "#ifndef SAFETY", + " && !a_cycles /* not in liveness mode */", + "#endif", + "#if SYNC", + " && boq == -1 /* not mid-rv */", + "#endif", + "#ifdef VERI", + " && (trpt->tau&4) /* claim moves first */", + " && !((trpt-1)->tau&128) /* not a stutter move */", + "#endif", + " && !(trpt->tau&8)) /* not an atomic move */", + " { int q = (core_id + 1) %% NCORE; /* circular handoff */", + " #ifdef GENEROUS", + " if (prcnt[q] < LN_FRAMES)", /* not the best strategy */ + " #else", + " if (TargetQ_NotFull(q)", + " && (dfs_phase2 == 0 || prcnt[core_id] > 0))", /* not locked, ok if race */ + " #endif", + " { mem_put(q);", /* only 1 writer: lock-free */ + " return 1;", + " }", + " { int rval;", + " #ifndef NGQ", + " rval = GlobalQ_HasRoom();", + " #else", + " rval = 0;", + " #endif", + " #ifdef USE_DISK", + " if (rval == 0)", + " { void mem_file(void);", + " mem_file();", + " rval = 1;", + " }", + " #endif", + " return rval;", + " }", + " }", + " return 0; /* i.e., no handoff */", + "}", + "", + "void", + "mem_put_acc(void) /* liveness mode */", + "{ int q = (core_id + 1) %% NCORE;", + "", + " if (search_terminated == NULL", + " || *search_terminated != 0)", + " { pan_exit(0);", + " }", + "#ifdef USE_DISK", + " mem_drain();", + "#endif", + " /* some tortured use of preprocessing: */", + "#if !defined(NGQ) || defined(USE_DISK)", + " if (TargetQ_Full(q))", + " {", + "#endif", + "#ifndef NGQ", + " if (GlobalQ_HasRoom())", + " { return;", + " }", + "#endif", + "#ifdef USE_DISK", + " mem_file();", + " } else", + "#else", + " #if !defined(NGQ) || defined(USE_DISK)", + " }", + " #endif", + "#endif", + " { mem_put(q);", + " }", + "}", + "", + "#if defined(WIN32) || defined(WIN64)", /* visual studio */ + "void", + "init_shm(void) /* initialize shared work-queues */", + "{ char key[512];", + " int n, m;", + " int must_exit = 0;", + "", + " if (core_id == 0 && verbose)", + " { printf(\"cpu0: step 3: allocate shared work-queues %%g Mb\\n\",", + " ((double) NCORE * LWQ_SIZE + GWQ_SIZE) / (1048576.));", + " }", + " for (m = 0; m < NR_QS; m++) /* last q is global 1 */", + " { double qsize = (m == NCORE) ? GWQ_SIZE : LWQ_SIZE;", + " sprintf(key, \"Global\\\\pan_%%s_%%.3d\", PanSource, m);", + " if (core_id == 0)", /* root process creates shared memory segments */ + " { shmid[m] = CreateFileMapping(", + " INVALID_HANDLE_VALUE, /* use paging file */", + " NULL, /* default security */", + " PAGE_READWRITE, /* access permissions */", + " 0, /* high-order 4 bytes */", + " qsize, /* low-order bytes, size in bytes */", + " key); /* name */", + " } else /* worker nodes just open these segments */", + " { shmid[m] = OpenFileMapping(", + " FILE_MAP_ALL_ACCESS, /* read/write access */", + " FALSE, /* children do not inherit handle */", + " key);", + " }", + " if (shmid[m] == NULL)", + " { fprintf(stderr, \"cpu%%d: could not create or open shared queues\\n\",", + " core_id);", + " must_exit = 1;", + " break;", + " }", + " /* attach: */", + " shared_mem[m] = (char *) MapViewOfFile(shmid[m], FILE_MAP_ALL_ACCESS, 0, 0, 0);", + " if (shared_mem[m] == NULL)", + " { fprintf(stderr, \"cpu%%d: cannot attach shared q%%d (%%d Mb)\\n\",", + " core_id, m+1, (int) (qsize/(1048576.)));", + " must_exit = 1;", + " break;", + " }", + "", + " memcnt += qsize;", + "", + " m_workq[m] = (SM_frame *) shared_mem[m];", + " if (core_id == 0)", + " { int nframes = (m == NCORE) ? GN_FRAMES : LN_FRAMES;", + " for (n = 0; n < nframes; n++)", + " { m_workq[m][n].m_vsize = 0;", + " m_workq[m][n].m_boq = 0;", + " } } }", + "", + " if (must_exit)", + " { fprintf(stderr, \"pan: check './pan --' for usage details\\n\");", + " pan_exit(1); /* calls cleanup_shm */", + " }", + "}", + "", + "static uchar *", + "prep_shmid_S(size_t n) /* either sets SS or H_tab, WIN32/WIN64 */", + "{ char *rval;", + "#ifndef SEP_STATE", + " char key[512];", + "", + " if (verbose && core_id == 0)", + " {", + " #ifdef BITSTATE", + " printf(\"cpu0: step 1: allocate shared bitstate %%g Mb\\n\",", + " (double) n / (1048576.));", + " #else", + " printf(\"cpu0: step 1: allocate shared hastable %%g Mb\\n\",", + " (double) n / (1048576.));", + " #endif", + " }", + " #ifdef MEMLIM", + " if (memcnt + (double) n > memlim)", + " { printf(\"cpu%%d: S %%8g + %%d Kb exceeds memory limit of %%8g Mb\\n\",", + " core_id, memcnt/1024., n/1024, memlim/(1048576.));", + " printf(\"cpu%%d: insufficient memory -- aborting\\n\", core_id);", + " exit(1);", + " }", + " #endif", + "", + " /* make key different from queues: */", + " sprintf(key, \"Global\\\\pan_%%s_%%.3d\", PanSource, NCORE+2); /* different from qs */", + "", + " if (core_id == 0) /* root */", + " { shmid_S = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,", + "#ifdef WIN64", + " PAGE_READWRITE, (n>>32), (n & 0xffffffff), key);", + "#else", + " PAGE_READWRITE, 0, n, key);", + "#endif", + " memcnt += (double) n;", + " } else /* worker */", + " { shmid_S = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, key);", + " }", + + " if (shmid_S == NULL)", + " {", + " #ifdef BITSTATE", + " fprintf(stderr, \"cpu%%d: cannot %%s shared bitstate\",", + " core_id, core_id?\"open\":\"create\");", + " #else", + " fprintf(stderr, \"cpu%%d: cannot %%s shared hashtable\",", + " core_id, core_id?\"open\":\"create\");", + " #endif", + " fprintf(stderr, \"pan: check './pan --' for usage details\\n\");", + " pan_exit(1);", + " }", + "", + " rval = (char *) MapViewOfFile(shmid_S, FILE_MAP_ALL_ACCESS, 0, 0, 0); /* attach */", + " if ((char *) rval == NULL)", + " { fprintf(stderr, \"cpu%%d: cannot attach shared bitstate or hashtable\\n\", core_id);", + " fprintf(stderr, \"pan: check './pan --' for usage details\\n\");", + " pan_exit(1);", + " }", + "#else", + " rval = (char *) emalloc(n);", + "#endif", + " return (uchar *) rval;", + "}", + "", + "static uchar *", + "prep_state_mem(size_t n) /* WIN32/WIN64 sets memory arena for states */", + "{ char *rval;", + " char key[512];", + " static int cnt = 3; /* start larger than earlier ftok calls */", + "", + " if (verbose && core_id == 0)", + " { printf(\"cpu0: step 2+: pre-allocate memory arena %%d of %%g Mb\\n\",", + " cnt-3, (double) n / (1048576.));", + " }", + " #ifdef MEMLIM", + " if (memcnt + (double) n > memlim)", + " { printf(\"cpu%%d: error: M %%.0f + %%.0f exceeds memory limit of %%.0f Kb\\n\",", + " core_id, memcnt/1024.0, (double) n/1024.0, memlim/1024.0);", + " return NULL;", + " }", + " #endif", + "", + " sprintf(key, \"Global\\\\pan_%%s_%%.3d\", PanSource, NCORE+cnt); cnt++;", + "", + " if (core_id == 0)", + " { shmid_M = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,", + "#ifdef WIN64", + " PAGE_READWRITE, (n>>32), (n & 0xffffffff), key);", + "#else", + " PAGE_READWRITE, 0, n, key);", + "#endif", + " } else", + " { shmid_M = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, key);", + " }", + " if (shmid_M == NULL)", + " { printf(\"cpu%%d: failed to get pool of shared memory nr %%d of size %%d\\n\",", + " core_id, cnt-3, n);", + " printf(\"pan: check './pan --' for usage details\\n\");", + " return NULL;", + " }", + " rval = (char *) MapViewOfFile(shmid_M, FILE_MAP_ALL_ACCESS, 0, 0, 0); /* attach */", + "", + " if (rval == NULL)", + " { printf(\"cpu%%d: failed to attach pool of shared memory nr %%d of size %%d\\n\",", + " core_id, cnt-3, n);", + " return NULL;", + " }", + " return (uchar *) rval;", + "}", + "", + "void", + "init_HT(unsigned long n) /* WIN32/WIN64 version */", + "{ volatile char *x;", + " double get_mem;", + "#ifndef SEP_STATE", + " char *dc_mem_start;", + "#endif", + " if (verbose) printf(\"cpu%%d: initialization for Windows\\n\", core_id);", + "", +"#ifdef SEP_STATE", + " #ifndef MEMLIM", + " if (verbose)", + " { printf(\"cpu0: steps 0,1: no -DMEMLIM set\\n\");", + " }", + " #else", + " if (verbose)", + " printf(\"cpu0: steps 0,1: -DMEMLIM=%%d Mb - (hashtable %%g Mb + workqueues %%g Mb)\\n\",", + " MEMLIM, ((double)n/(1048576.)), ((double) NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.));", + "#endif", + " get_mem = NCORE * sizeof(double) + (1 + CS_NR) * sizeof(void *)+ 4*sizeof(void *) + 2*sizeof(double);", + " /* NCORE * is_alive + search_terminated + CS_NR * sh_lock + 6 gr vars */", + " get_mem += 4 * NCORE * sizeof(void *);", /* prfree, prfull, prcnt, prmax */ + " #ifdef FULL_TRAIL", + " get_mem += (NCORE) * sizeof(Stack_Tree *);", + " /* NCORE * stack_last */", + " #endif", + " x = (volatile char *) prep_state_mem((size_t) get_mem);", + " shmid_X = (void *) x;", + " if (x == NULL)", + " { printf(\"cpu0: could not allocate shared memory, see ./pan --\\n\");", + " exit(1);", + " }", + " search_terminated = (volatile unsigned int *) x; /* comes first */", + " x += sizeof(void *); /* maintain alignment */", + "", + " is_alive = (volatile double *) x;", + " x += NCORE * sizeof(double);", + "", + " sh_lock = (volatile int *) x;", + " x += CS_NR * sizeof(void *); /* allow 1 word per entry */", + "", + " grfree = (volatile int *) x;", + " x += sizeof(void *);", + " grfull = (volatile int *) x;", + " x += sizeof(void *);", + " grcnt = (volatile int *) x;", + " x += sizeof(void *);", + " grmax = (volatile int *) x;", + " x += sizeof(void *);", + " prfree = (volatile int *) x;", + " x += NCORE * sizeof(void *);", + " prfull = (volatile int *) x;", + " x += NCORE * sizeof(void *);", + " prcnt = (volatile int *) x;", + " x += NCORE * sizeof(void *);", + " prmax = (volatile int *) x;", + " x += NCORE * sizeof(void *);", + " gr_readmiss = (volatile double *) x;", + " x += sizeof(double);", + " gr_writemiss = (volatile double *) x;", + " x += sizeof(double);", + "", + " #ifdef FULL_TRAIL", + " stack_last = (volatile Stack_Tree **) x;", + " x += NCORE * sizeof(Stack_Tree *);", + " #endif", + "", + " #ifndef BITSTATE", + " H_tab = (H_el **) emalloc(n);", + " #endif", +"#else", + " #ifndef MEMLIM", + " #warning MEMLIM not set", /* cannot happen */ + " #define MEMLIM (2048)", + " #endif", + "", + " if (core_id == 0 && verbose)", + " printf(\"cpu0: step 0: -DMEMLIM=%%d Mb - (hashtable %%g Mb + workqueues %%g Mb) = %%g Mb for state storage\\n\",", + " MEMLIM, ((double)n/(1048576.)), ((double) NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.),", + " (memlim - memcnt - (double) n - ((double) NCORE * LWQ_SIZE + GWQ_SIZE))/(1048576.));", + " #ifndef BITSTATE", + " H_tab = (H_el **) prep_shmid_S((size_t) n); /* hash_table */", + " #endif", + " get_mem = memlim - memcnt - ((double) NCORE) * LWQ_SIZE - GWQ_SIZE;", + " if (get_mem <= 0)", + " { Uerror(\"internal error -- shared state memory\");", + " }", + "", + " if (core_id == 0 && verbose)", + " { printf(\"cpu0: step 2: shared state memory %%g Mb\\n\",", + " get_mem/(1048576.));", + " }", + " x = dc_mem_start = (char *) prep_state_mem((size_t) get_mem); /* for states */", + " if (x == NULL)", + " { printf(\"cpu%%d: insufficient memory -- aborting\\n\", core_id);", + " exit(1);", + " }", + "", + " search_terminated = (volatile unsigned int *) x; /* comes first */", + " x += sizeof(void *); /* maintain alignment */", + "", + " is_alive = (volatile double *) x;", + " x += NCORE * sizeof(double);", + "", + " sh_lock = (volatile int *) x;", + " x += CS_NR * sizeof(int);", + "", + " grfree = (volatile int *) x;", + " x += sizeof(void *);", + " grfull = (volatile int *) x;", + " x += sizeof(void *);", + " grcnt = (volatile int *) x;", + " x += sizeof(void *);", + " grmax = (volatile int *) x;", + " x += sizeof(void *);", + " prfree = (volatile int *) x;", + " x += NCORE * sizeof(void *);", + " prfull = (volatile int *) x;", + " x += NCORE * sizeof(void *);", + " prcnt = (volatile int *) x;", + " x += NCORE * sizeof(void *);", + " prmax = (volatile int *) x;", + " x += NCORE * sizeof(void *);", + " gr_readmiss = (volatile double *) x;", + " x += sizeof(double);", + " gr_writemiss = (volatile double *) x;", + " x += sizeof(double);", + "", + " #ifdef FULL_TRAIL", + " stack_last = (volatile Stack_Tree **) x;", + " x += NCORE * sizeof(Stack_Tree *);", + " #endif", + " if (((long)x)&(sizeof(void *)-1)) /* word alignment */", + " { x += sizeof(void *)-(((long)x)&(sizeof(void *)-1)); /* 64-bit align */", + " }", + "", + " #ifdef COLLAPSE", + " ncomps = (unsigned long *) x;", + " x += (256+2) * sizeof(unsigned long);", + " #endif", + "", + " dc_shared = (sh_Allocater *) x; /* in shared memory */", + " x += sizeof(sh_Allocater);", + "", + " if (core_id == 0) /* root only */", + " { dc_shared->dc_id = shmid_M;", + " dc_shared->dc_start = (void *) dc_mem_start;", + " dc_shared->dc_arena = x;", + " dc_shared->pattern = 1234567;", + " dc_shared->dc_size = (long) get_mem - (long) (x - dc_mem_start);", + " dc_shared->nxt = NULL;", + " }", +"#endif", + "}", + "", + "#if defined(WIN32) || defined(WIN64) || defined(__i386__) || defined(__x86_64__)", + "extern BOOLEAN InterlockedBitTestAndSet(LONG volatile* Base, LONG Bit);", + "int", + "tas(volatile LONG *s)", /* atomic test and set */ + "{ return InterlockedBitTestAndSet(s, 1);", + "}", + "#else", + " #error missing definition of test and set operation for this platform", + "#endif", + "", + "void", + "cleanup_shm(int val)", + "{ int m;", + " static int nibis = 0;", + "", + " if (nibis != 0)", + " { printf(\"cpu%%d: Redundant call to cleanup_shm(%%d)\\n\", core_id, val);", + " return;", + " } else", + " { nibis = 1;", + " }", + " if (search_terminated != NULL)", + " { *search_terminated |= 16; /* cleanup_shm */", + " }", + "", + " for (m = 0; m < NR_QS; m++)", + " { if (shmid[m] != NULL)", + " { UnmapViewOfFile((char *) shared_mem[m]);", + " CloseHandle(shmid[m]);", + " } }", + "#ifdef SEP_STATE", + " UnmapViewOfFile((void *) shmid_X);", + " CloseHandle((void *) shmid_M);", + "#else", + " #ifdef BITSTATE", + " if (shmid_S != NULL)", + " { UnmapViewOfFile(SS);", + " CloseHandle(shmid_S);", + " }", + " #else", + " if (core_id == 0 && verbose)", + " { printf(\"cpu0: done, %%ld Mb of shared state memory left\\n\",", + " dc_shared->dc_size / (long)(1048576));", + " }", + " if (shmid_S != NULL)", + " { UnmapViewOfFile(H_tab);", + " CloseHandle(shmid_S);", + " }", + " shmid_M = (void *) (dc_shared->dc_id);", + " UnmapViewOfFile((char *) dc_shared->dc_start);", + " CloseHandle(shmid_M);", + " #endif", + "#endif", + " /* detached from shared memory - so cannot use cpu_printf */", + " if (verbose)", + " { printf(\"cpu%%d: done -- got %%d states from queue\\n\",", + " core_id, nstates_get);", + " }", + "}", + "", + "void", + "mem_get(void)", + "{ SM_frame *f;", + " int is_parent;", + "", + "#if defined(MA) && !defined(SEP_STATE)", + " #error MA requires SEP_STATE in multi-core mode", + "#endif", + "#ifdef BFS", + " #error instead of -DNCORE -DBFS use -DBFS_PAR", + "#endif", + "#ifdef SC", + " #error SC is not supported in multi-core mode", + "#endif", + " init_shm(); /* we are single threaded when this starts */", + " signal(SIGINT, give_up); /* windows control-c interrupt */", + "", + " if (core_id == 0 && verbose)", + " { printf(\"cpu0: step 4: creating additional workers (proxy %%d)\\n\",", + " proxy_pid);", + " }", + "#if 0", + " if NCORE > 1 the child or the parent should fork N-1 more times", + " the parent is the only process with core_id == 0 and is_parent > 0", + " the others (workers) have is_parent = 0 and core_id = 1..NCORE-1", + "#endif", + " if (core_id == 0) /* root starts up the workers */", + " { worker_pids[0] = (DWORD) getpid(); /* for completeness */", + " while (++core_id < NCORE) /* first worker sees core_id = 1 */", + " { char cmdline[64];", + " STARTUPINFO si = { sizeof(si) };", + " PROCESS_INFORMATION pi;", + "", + " if (proxy_pid == core_id) /* always non-zero */", + " { sprintf(cmdline, \"pan_proxy.exe -r %%s-Q%%d -Z%%d\",", + " o_cmdline, getpid(), core_id);", + " } else", + " { sprintf(cmdline, \"pan.exe %%s-Q%%d -Z%%d\",", + " o_cmdline, getpid(), core_id);", + " }", + " if (verbose) printf(\"cpu%%d: spawn %%s\\n\", core_id, cmdline);", + "", + " is_parent = CreateProcess(0, cmdline, 0, 0, FALSE, 0, 0, 0, &si, &pi);", + " if (is_parent == 0)", + " { Uerror(\"fork failed\");", + " }", + " worker_pids[core_id] = pi.dwProcessId;", + " worker_handles[core_id] = pi.hProcess;", + " if (verbose)", + " { cpu_printf(\"created core %%d, pid %%d\\n\",", + " core_id, pi.dwProcessId);", + " }", + " if (proxy_pid == core_id) /* we just created the receive half */", + " { /* add proxy send, store pid in proxy_pid_snd */", + " sprintf(cmdline, \"pan_proxy.exe -s %%s-Q%%d -Z%%d -Y%%d\",", + " o_cmdline, getpid(), core_id, worker_pids[proxy_pid]);", + " if (verbose) printf(\"cpu%%d: spawn %%s\\n\", core_id, cmdline);", + " is_parent = CreateProcess(0, cmdline, 0,0, FALSE, 0,0,0, &si, &pi);", + " if (is_parent == 0)", + " { Uerror(\"fork failed\");", + " }", + " proxy_pid_snd = pi.dwProcessId;", + " proxy_handle_snd = pi.hProcess;", + " if (verbose)", + " { cpu_printf(\"created core %%d, pid %%d (send proxy)\\n\",", + " core_id, pi.dwProcessId);", + " } } }", + " core_id = 0; /* reset core_id for root process */", + " } else /* worker */", + " { static char db0[16]; /* good for up to 10^6 cores */", + " static char db1[16];", + " tprefix = db0; sprefix = db1;", + " sprintf(tprefix, \"cpu%%d_trail\", core_id); /* avoid conflicts on file access */", + " sprintf(sprefix, \"cpu%%d_rst\", core_id);", + " memcnt = 0; /* count only additionally allocated memory */", + " }", + " if (verbose)", + " { cpu_printf(\"starting core_id %%d -- pid %%d\\n\", core_id, getpid());", + " }", + " if (core_id == 0 && !remote_party)", + " { new_state(); /* root starts the search */", + " if (verbose)", + " cpu_printf(\"done with 1st dfs, nstates %%g (put %%d states), start reading q\\n\",", + " nstates, nstates_put);", + " dfs_phase2 = 1;", + " }", + " Read_Queue(core_id); /* all cores */", + "", + " if (verbose)", + " { cpu_printf(\"put %%6d states into queue -- got %%6d\\n\",", + " nstates_put, nstates_get);", + " }", + " done = 1;", + " wrapup();", + " exit(0);", + "}", + "#endif", /* WIN32 || WIN64 */ + "", + "#ifdef BITSTATE", + "void", + "init_SS(unsigned long n)", + "{", + " SS = (uchar *) prep_shmid_S((size_t) n);", + " init_HT(0L);", /* locks and shared memory for Stack_Tree allocations */ + "}", + "#endif", /* BITSTATE */ + "", + "#endif", /* NCORE>1 */ + 0, +}; diff --git a/sys/src/cmd/spin/pangen7.c b/sys/src/cmd/spin/pangen7.c new file mode 100644 index 000000000..37f461fbe --- /dev/null +++ b/sys/src/cmd/spin/pangen7.c @@ -0,0 +1,923 @@ +/***** spin: pangen7.c *****/ + +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ + +#include +#include +#include "spin.h" +#include "y.tab.h" +#include +#ifndef PC +#include +#endif + +extern ProcList *rdy; +extern Element *Al_El; +extern int nclaims, verbose, Strict; +extern short has_accept; + +typedef struct Succ_List Succ_List; +typedef struct SQueue SQueue; +typedef struct OneState OneState; +typedef struct State_Stack State_Stack; +typedef struct Guard Guard; + +struct Succ_List { + SQueue *s; + Succ_List *nxt; +}; + +struct OneState { + int *combo; /* the combination of claim states */ + Succ_List *succ; /* list of ptrs to immediate successor states */ +}; + +struct SQueue { + OneState state; + SQueue *nxt; +}; + +struct State_Stack { + int *n; + State_Stack *nxt; +}; + +struct Guard { + Lextok *t; + Guard *nxt; +}; + +static SQueue *sq, *sd, *render; /* states move from sq to sd to render to holding */ +static SQueue *holding, *lasthold; +static State_Stack *dsts; + +static int nst; /* max nr of states in claims */ +static int *Ist; /* initial states */ +static int *Nacc; /* number of accept states in claim */ +static int *Nst; /* next states */ +static int **reached; /* n claims x states */ +static int unfolding; /* to make sure all accept states are reached */ +static int is_accept; /* remember if the current state is accepting in any claim */ +static int not_printing; /* set during explore_product */ + +static Element ****matrix; /* n x two-dimensional arrays state x state */ +static Element **Selfs; /* self-loop states at end of claims */ + +static void get_seq(int, Sequence *); +static void set_el(int n, Element *e); +static void gen_product(void); +static void print_state_nm(char *, int *, char *); +static SQueue *find_state(int *); +static SQueue *retrieve_state(int *); + +static int +same_state(int *a, int *b) +{ int i; + + for (i = 0; i < nclaims; i++) + { if (a[i] != b[i]) + { return 0; + } } + return 1; +} + +static int +in_stack(SQueue *s, SQueue *in) +{ SQueue *q; + + for (q = in; q; q = q->nxt) + { if (same_state(q->state.combo, s->state.combo)) + { return 1; + } } + return 0; +} + +static void +to_render(SQueue *s) +{ SQueue *a, *q, *last; /* find in sd/sq and move to render, if not already there */ + int n; + + for (n = 0; n < nclaims; n++) + { reached[n][ s->state.combo[n] ] |= 2; + } + + for (q = render; q; q = q->nxt) + { if (same_state(q->state.combo, s->state.combo)) + { return; + } } + for (q = holding; q; q = q->nxt) + { if (same_state(q->state.combo, s->state.combo)) + { return; + } } + + a = sd; +more: + for (q = a, last = 0; q; last = q, q = q->nxt) + { if (same_state(q->state.combo, s->state.combo)) + { if (!last) + { if (a == sd) + { sd = q->nxt; + } else if (a == sq) + { sq = q->nxt; + } else + { holding = q->nxt; + } + } else + { last->nxt = q->nxt; + } + q->nxt = render; + render = q; + return; + } } + if (verbose) + { print_state_nm("looking for: ", s->state.combo, "\n"); + } + (void) find_state(s->state.combo); /* creates it in sq */ + if (a != sq) + { a = sq; + goto more; + } + fatal("cannot happen, to_render", 0); +} + +static void +wrap_text(char *pre, Lextok *t, char *post) +{ + printf(pre, (char *) 0); + comment(stdout, t, 0); + printf(post, (char *) 0); +} + +static State_Stack * +push_dsts(int *n) +{ State_Stack *s; + int i; + + for (s = dsts; s; s = s->nxt) + { if (same_state(s->n, n)) + { if (verbose&64) + { printf("\n"); + for (s = dsts; s; s = s->nxt) + { print_state_nm("\t", s->n, "\n"); + } + print_state_nm("\t", n, "\n"); + } + return s; + } } + + s = (State_Stack *) emalloc(sizeof(State_Stack)); + s->n = (int *) emalloc(nclaims * sizeof(int)); + for (i = 0; i < nclaims; i++) + s->n[i] = n[i]; + s->nxt = dsts; + dsts = s; + return 0; +} + +static void +pop_dsts(void) +{ + assert(dsts != NULL); + dsts = dsts->nxt; +} + +static void +complete_transition(Succ_List *sl, Guard *g) +{ Guard *w; + int cnt = 0; + + printf(" :: "); + for (w = g; w; w = w->nxt) + { if (w->t->ntyp == CONST + && w->t->val == 1) + { continue; + } else if (w->t->ntyp == 'c' + && w->t->lft->ntyp == CONST + && w->t->lft->val == 1) + { continue; /* 'true' */ + } + + if (cnt > 0) + { printf(" && "); + } + wrap_text("", w->t, ""); + cnt++; + } + if (cnt == 0) + { printf("true"); + } + print_state_nm(" -> goto ", sl->s->state.combo, ""); + + if (is_accept > 0) + { printf("_U%d\n", (unfolding+1)%nclaims); + } else + { printf("_U%d\n", unfolding); + } +} + +static void +state_body(OneState *s, Guard *guard) +{ Succ_List *sl; + State_Stack *y; + Guard *g; + int i, once; + + for (sl = s->succ; sl; sl = sl->nxt) + { once = 0; + + for (i = 0; i < nclaims; i++) + { Element *e; + e = matrix[i][s->combo[i]][sl->s->state.combo[i]]; + + /* if one of the claims has a DO or IF move + then pull its target state forward, once + */ + + if (!e + || e->n->ntyp == NON_ATOMIC + || e->n->ntyp == DO + || e->n->ntyp == IF) + { s = &(sl->s->state); + y = push_dsts(s->combo); + if (!y) + { if (once++ == 0) + { assert(s->succ != NULL); + state_body(s, guard); + } + pop_dsts(); + } else if (!y->nxt) /* self-loop transition */ + { if (!not_printing) printf(" /* self-loop */\n"); + } else + { /* non_fatal("loop in state body", 0); ** maybe ok */ + } + continue; + } else + { g = (Guard *) emalloc(sizeof(Guard)); + g->t = e->n; + g->nxt = guard; + guard = g; + } } + + if (guard && !once) + { if (!not_printing) complete_transition(sl, guard); + to_render(sl->s); + } } +} + +static struct X { + char *s; int n; +} spl[] = { + {"end", 3 }, + {"accept", 6 }, + {0, 0 }, +}; + +static int slcnt; +extern Label *labtab; + +static ProcList * +locate_claim(int n) +{ ProcList *p; + int i; + + for (p = rdy, i = 0; p; p = p->nxt, i++) /* find claim name */ + { if (i == n) + { break; + } } + assert(p && p->b == N_CLAIM); + + return p; +} + +static void +elim_lab(Element *e) +{ Label *l, *lst; + + for (l = labtab, lst = NULL; l; lst = l, l = l->nxt) + { if (l->e == e) + { if (lst) + { lst->nxt = l->nxt; + } else + { labtab = l->nxt; + } + break; + } } +} + +static int +claim_has_accept(ProcList *p) +{ Label *l; + + for (l = labtab; l; l = l->nxt) + { if (strcmp(l->c->name, p->n->name) == 0 + && strncmp(l->s->name, "accept", 6) == 0) + { return 1; + } } + return 0; +} + +static void +prune_accept(void) +{ int n; + + for (n = 0; n < nclaims; n++) + { if ((reached[n][Selfs[n]->seqno] & 2) == 0) + { if (verbose) + { printf("claim %d: selfloop not reachable\n", n); + } + elim_lab(Selfs[n]); + Nacc[n] = claim_has_accept(locate_claim(n)); + } } +} + +static void +mk_accepting(int n, Element *e) +{ ProcList *p; + Label *l; + int i; + + assert(!Selfs[n]); + Selfs[n] = e; + + l = (Label *) emalloc(sizeof(Label)); + l->s = (Symbol *) emalloc(sizeof(Symbol)); + l->s->name = "accept00"; + l->c = (Symbol *) emalloc(sizeof(Symbol)); + l->uiid = 0; /* this is not in an inline */ + + for (p = rdy, i = 0; p; p = p->nxt, i++) /* find claim name */ + { if (i == n) + { l->c->name = p->n->name; + break; + } } + assert(p && p->b == N_CLAIM); + Nacc[n] = 1; + has_accept = 1; + + l->e = e; + l->nxt = labtab; + labtab = l; +} + +static void +check_special(int *nrs) +{ ProcList *p; + Label *l; + int i, j, nmatches; + int any_accepts = 0; + + for (i = 0; i < nclaims; i++) + { any_accepts += Nacc[i]; + } + + is_accept = 0; + for (j = 0; spl[j].n; j++) /* 2 special label prefixes */ + { nmatches = 0; + for (p = rdy, i = 0; p; p = p->nxt, i++) /* check each claim */ + { if (p->b != N_CLAIM) + { continue; + } + /* claim i in state nrs[i], type p->tn, name p->n->name + * either the state has an accept label, or the claim has none, + * so that all its states should be considered accepting + * --- but only if other claims do have accept states! + */ + if (Strict == 0 && j == 1 && Nacc[i] == 0 && any_accepts > 0) + { if ((verbose&32) && i == unfolding) + { printf(" /* claim %d pseudo-accept */\n", i); + } + goto is_accepting; + } + for (l = labtab; l; l = l->nxt) /* check its labels */ + { if (strcmp(l->c->name, p->n->name) == 0 /* right claim */ + && l->e->seqno == nrs[i] /* right state */ + && strncmp(l->s->name, spl[j].s, spl[j].n) == 0) + { if (j == 1) /* accept state */ + { char buf[32]; +is_accepting: if (strchr(p->n->name, ':')) + { sprintf(buf, "N%d", i); + } else + { assert(strlen(p->n->name) < sizeof(buf)); + strcpy(buf, p->n->name); + } + if (unfolding == 0 && i == 0) + { if (!not_printing) + printf("%s_%s_%d:\n", /* true accept */ + spl[j].s, buf, slcnt++); + } else if (verbose&32) + { if (!not_printing) + printf("%s_%s%d:\n", + buf, spl[j].s, slcnt++); + } + if (i == unfolding) + { is_accept++; /* move to next unfolding */ + } + } else + { nmatches++; + } + break; + } } } + if (j == 0 && nmatches == nclaims) /* end-state */ + { if (!not_printing) + { printf("%s%d:\n", spl[j].s, slcnt++); + } } } +} + +static int +render_state(SQueue *q) +{ + if (!q || !q->state.succ) + { if (verbose&64) + { printf(" no exit\n"); + } + return 0; + } + + check_special(q->state.combo); /* accept or end-state labels */ + + dsts = (State_Stack *) 0; + push_dsts(q->state.combo); /* to detect loops */ + + if (!not_printing) + { print_state_nm("", q->state.combo, ""); /* the name */ + printf("_U%d:\n\tdo\n", unfolding); + } + + state_body(&(q->state), (Guard *) 0); + + if (!not_printing) + { printf("\tod;\n"); + } + pop_dsts(); + return 1; +} + +static void +explore_product(void) +{ SQueue *q; + + /* all states are in the sd queue */ + + q = retrieve_state(Ist); /* retrieve from the sd q */ + q->nxt = render; /* put in render q */ + render = q; + do { + q = render; + render = render->nxt; + q->nxt = 0; /* remove from render q */ + + if (verbose&64) + { print_state_nm("explore: ", q->state.combo, "\n"); + } + + not_printing = 1; + render_state(q); /* may add new states */ + not_printing = 0; + + if (lasthold) + { lasthold->nxt = q; + lasthold = q; + } else + { holding = lasthold = q; + } + } while (render); + assert(!dsts); + +} + +static void +print_product(void) +{ SQueue *q; + int cnt; + + if (unfolding == 0) + { printf("never Product {\n"); /* name expected by iSpin */ + q = find_state(Ist); /* should find it in the holding q */ + assert(q != NULL); + q->nxt = holding; /* put it at the front */ + holding = q; + } + render = holding; + holding = lasthold = 0; + + printf("/* ============= U%d ============= */\n", unfolding); + cnt = 0; + do { + q = render; + render = render->nxt; + q->nxt = 0; + if (verbose&64) + { print_state_nm("print: ", q->state.combo, "\n"); + } + cnt += render_state(q); + + if (lasthold) + { lasthold->nxt = q; + lasthold = q; + } else + { holding = lasthold = q; + } + } while (render); + assert(!dsts); + + if (cnt == 0) + { printf(" 0;\n"); + } + + if (unfolding == nclaims-1) + { printf("}\n"); + } +} + +static void +prune_dead(void) +{ Succ_List *sl, *last; + SQueue *q; + int cnt; + + do { cnt = 0; + for (q = sd; q; q = q->nxt) + { /* if successor is deadend, remove it + * unless it's a move to the end-state of the claim + */ + last = (Succ_List *) 0; + for (sl = q->state.succ; sl; last = sl, sl = sl->nxt) + { if (!sl->s->state.succ) /* no successor */ + { if (!last) + { q->state.succ = sl->nxt; + } else + { last->nxt = sl->nxt; + } + cnt++; + } } } + } while (cnt > 0); +} + +static void +print_raw(void) +{ int i, j, n; + + printf("#if 0\n"); + for (n = 0; n < nclaims; n++) + { printf("C%d:\n", n); + for (i = 0; i < nst; i++) + { if (reached[n][i]) + for (j = 0; j < nst; j++) + { if (matrix[n][i][j]) + { if (reached[n][i] & 2) printf("+"); + if (i == Ist[n]) printf("*"); + printf("\t%d", i); + wrap_text(" -[", matrix[n][i][j]->n, "]->\t"); + printf("%d\n", j); + } } } } + printf("#endif\n\n"); + fflush(stdout); +} + +void +sync_product(void) +{ ProcList *p; + Element *e; + int n, i; + + if (nclaims <= 1) return; + + (void) unlink("pan.pre"); + + Ist = (int *) emalloc(sizeof(int) * nclaims); + Nacc = (int *) emalloc(sizeof(int) * nclaims); + Nst = (int *) emalloc(sizeof(int) * nclaims); + reached = (int **) emalloc(sizeof(int *) * nclaims); + Selfs = (Element **) emalloc(sizeof(Element *) * nclaims); + matrix = (Element ****) emalloc(sizeof(Element ***) * nclaims); /* claims */ + + for (p = rdy, i = 0; p; p = p->nxt, i++) + { if (p->b == N_CLAIM) + { nst = max(p->s->maxel, nst); + Nacc[i] = claim_has_accept(p); + } } + + for (n = 0; n < nclaims; n++) + { reached[n] = (int *) emalloc(sizeof(int) * nst); + matrix[n] = (Element ***) emalloc(sizeof(Element **) * nst); /* rows */ + for (i = 0; i < nst; i++) /* cols */ + { matrix[n][i] = (Element **) emalloc(sizeof(Element *) * nst); + } } + + for (e = Al_El; e; e = e->Nxt) + { e->status &= ~DONE; + } + + for (p = rdy, n=0; p; p = p->nxt, n++) + { if (p->b == N_CLAIM) + { /* fill in matrix[n] */ + e = p->s->frst; + Ist[n] = huntele(e, e->status, -1)->seqno; + + reached[n][Ist[n]] = 1|2; + get_seq(n, p->s); + } } + + if (verbose) /* show only the input automata */ + { print_raw(); + } + + gen_product(); /* create product automaton */ +} + +static int +nxt_trans(int n, int cs, int frst) +{ int j; + + for (j = frst; j < nst; j++) + { if (reached[n][cs] + && matrix[n][cs][j]) + { return j; + } } + return -1; +} + +static void +print_state_nm(char *p, int *s, char *a) +{ int i; + printf("%sP", p); + for (i = 0; i < nclaims; i++) + { printf("_%d", s[i]); + } + printf("%s", a); +} + +static void +create_transition(OneState *s, SQueue *it) +{ int n, from, upto; + int *F = s->combo; + int *T = it->state.combo; + Succ_List *sl; + Lextok *t; + + if (verbose&64) + { print_state_nm("", F, " "); + print_state_nm("-> ", T, "\t"); + } + + /* check if any of the claims is blocked */ + /* which makes the state a dead-end */ + for (n = 0; n < nclaims; n++) + { from = F[n]; + upto = T[n]; + t = matrix[n][from][upto]->n; + if (verbose&64) + { wrap_text("", t, " "); + } + if (t->ntyp == 'c' + && t->lft->ntyp == CONST) + { if (t->lft->val == 0) /* i.e., false */ + { goto done; + } } } + + sl = (Succ_List *) emalloc(sizeof(Succ_List)); + sl->s = it; + sl->nxt = s->succ; + s->succ = sl; +done: + if (verbose&64) + { printf("\n"); + } +} + +static SQueue * +find_state(int *cs) +{ SQueue *nq, *a = sq; + int i; + +again: /* check in nq, sq, and then in the render q */ + for (nq = a; nq; nq = nq->nxt) + { if (same_state(nq->state.combo, cs)) + { return nq; /* found */ + } } + if (a == sq && sd) + { a = sd; + goto again; /* check the other stack too */ + } else if (a == sd && render) + { a = render; + goto again; + } + + nq = (SQueue *) emalloc(sizeof(SQueue)); + nq->state.combo = (int *) emalloc(nclaims * sizeof(int)); + for (i = 0; i < nclaims; i++) + { nq->state.combo[i] = cs[i]; + } + nq->nxt = sq; /* add to sq stack */ + sq = nq; + + return nq; +} + +static SQueue * +retrieve_state(int *s) +{ SQueue *nq, *last = NULL; + + for (nq = sd; nq; last = nq, nq = nq->nxt) + { if (same_state(nq->state.combo, s)) + { if (last) + { last->nxt = nq->nxt; + } else + { sd = nq->nxt; /* 6.4.0: was sd = nq */ + } + return nq; /* found */ + } } + + fatal("cannot happen: retrieve_state", 0); + return (SQueue *) 0; +} + +static void +all_successors(int n, OneState *cur) +{ int i, j = 0; + + if (n >= nclaims) + { create_transition(cur, find_state(Nst)); + } else + { i = cur->combo[n]; + for (;;) + { j = nxt_trans(n, i, j); + if (j < 0) break; + Nst[n] = j; + all_successors(n+1, cur); + j++; + } } +} + +static void +gen_product(void) +{ OneState *cur_st; + SQueue *q; + + find_state(Ist); /* create initial state */ + + while (sq) + { if (in_stack(sq, sd)) + { sq = sq->nxt; + continue; + } + cur_st = &(sq->state); + + q = sq; + sq = sq->nxt; /* delete from sq stack */ + q->nxt = sd; /* and move to done stack */ + sd = q; + + all_successors(0, cur_st); + } + /* all states are in the sd queue now */ + prune_dead(); + explore_product(); /* check if added accept-self-loops are reachable */ + prune_accept(); + + if (verbose) + { print_raw(); + } + + /* PM: merge states with identical successor lists */ + + /* all outgoing transitions from accept-states + from claim n in copy n connect to states in copy (n+1)%nclaims + only accept states from claim 0 in copy 0 are true accept states + in the product + + PM: what about claims that have no accept states (e.g., restrictions) + */ + + for (unfolding = 0; unfolding < nclaims; unfolding++) + { print_product(); + } +} + +static void +t_record(int n, Element *e, Element *g) +{ int from = e->seqno, upto = g?g->seqno:0; + + assert(from >= 0 && from < nst); + assert(upto >= 0 && upto < nst); + + matrix[n][from][upto] = e; + reached[n][upto] |= 1; +} + +static void +get_sub(int n, Element *e) +{ + if (e->n->ntyp == D_STEP + || e->n->ntyp == ATOMIC) + { fatal("atomic or d_step in never claim product", 0); + } + /* NON_ATOMIC */ + e->n->sl->this->last->nxt = e->nxt; + get_seq(n, e->n->sl->this); + + t_record(n, e, e->n->sl->this->frst); + +} + +static void +set_el(int n, Element *e) +{ Element *g; + + if (e->n->ntyp == '@') /* change to self-loop */ + { e->n->ntyp = CONST; + e->n->val = 1; /* true */ + e->nxt = e; + g = e; + mk_accepting(n, e); + } else + + if (e->n->ntyp == GOTO) + { g = get_lab(e->n, 1); + g = huntele(g, e->status, -1); + } else if (e->nxt) + { g = huntele(e->nxt, e->status, -1); + } else + { g = NULL; + } + + t_record(n, e, g); +} + +static void +get_seq(int n, Sequence *s) +{ SeqList *h; + Element *e; + + e = huntele(s->frst, s->frst->status, -1); + for ( ; e; e = e->nxt) + { if (e->status & DONE) + { goto checklast; + } + e->status |= DONE; + + if (e->n->ntyp == UNLESS) + { fatal("unless stmnt in never claim product", 0); + } + + if (e->sub) /* IF or DO */ + { Lextok *x = NULL; + Lextok *y = NULL; + Lextok *haselse = NULL; + + for (h = e->sub; h; h = h->nxt) + { Lextok *t = h->this->frst->n; + if (t->ntyp == ELSE) + { if (verbose&64) printf("else at line %d\n", t->ln); + haselse = t; + continue; + } + if (t->ntyp != 'c') + { fatal("product, 'else' combined with non-condition", 0); + } + + if (t->lft->ntyp == CONST /* true */ + && t->lft->val == 1 + && y == NULL) + { y = nn(ZN, CONST, ZN, ZN); + y->val = 0; + } else + { if (!x) + x = t; + else + x = nn(ZN, OR, x, t); + if (verbose&64) + { wrap_text(" [", x, "]\n"); + } } } + if (haselse) + { if (!y) + { y = nn(ZN, '!', x, ZN); + } + if (verbose&64) + { wrap_text(" [else: ", y, "]\n"); + } + haselse->ntyp = 'c'; /* replace else */ + haselse->lft = y; + } + + for (h = e->sub; h; h = h->nxt) + { t_record(n, e, h->this->frst); + get_seq(n, h->this); + } + } else + { if (e->n->ntyp == ATOMIC + || e->n->ntyp == D_STEP + || e->n->ntyp == NON_ATOMIC) + { get_sub(n, e); + } else + { set_el(n, e); + } + } +checklast: if (e == s->last) + break; + } +} diff --git a/sys/src/cmd/spin/pangen7.h b/sys/src/cmd/spin/pangen7.h new file mode 100644 index 000000000..e0af0b512 --- /dev/null +++ b/sys/src/cmd/spin/pangen7.h @@ -0,0 +1,2413 @@ +/***** spin: pangen7.h *****/ + +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ + +static const char *pan_par[] = { /* generates pan.p */ + "#include ", + "#include ", + "#include ", /* for nanosleep */ + "#include ", + "#include ", + "#ifdef BFS_DISK", + "#include ", /* for rmdir */ + "#include ", /* for mkdir */ + "#include ", + "#include ", /* for open */ + "#endif", + "", + "#define Max(a,b) (((a)>(b))?(a):(b))", + "#ifndef WAIT_MAX", + " #define WAIT_MAX 2 /* seconds */", + "#endif", + "#define BFS_GEN 2 /* current and next generation */", + "", + "typedef struct BFS_Slot BFS_Slot;", + "typedef struct BFS_shared BFS_shared;", + "typedef struct BFS_data BFS_data;", + "", + "struct BFS_Slot {", + " #ifdef BFS_FIFO", + " enum bfs_types type; /* message type */", + " #endif", + " BFS_State *s_data; /* state data */", + " #ifndef BFS_QSZ", + " BFS_Slot *nxt; /* linked list */", + " #endif", + "};", + "", + "struct BFS_data {", + " double memcnt;", + " double nstates;", + " double nlinks;", + " double truncs;", + " ulong mreached;", + " ulong vsize;", + " ulong memory_left;", + " ulong punted;", + " ulong errors;", + " int override; /* after crash, if another proc clears locks */", + "};", + "", + "struct BFS_shared { /* about 13K for BFS_MAXPROCS=16 and BFS_MAXLOCKS=1028 */", + " volatile ulong quit; /* set to signal termination -- one word */", + " volatile ulong started;", + "", + " volatile uchar sh_owner[BFS_MAXLOCKS]; /* optional */", + "#ifdef BFS_CHECK", + " volatile uchar in_count[BFS_MAXLOCKS]; /* optional */", + "#endif", + " volatile int sh_locks[BFS_MAXLOCKS];", + " volatile ulong wait_count[BFS_MAXLOCKS]; /* optional */", + "", + " volatile BFS_data bfs_data[BFS_MAXPROCS];", + " volatile uchar bfs_flag[BFS_MAXPROCS]; /* running 0, normal exit 1, abnormal 2 */", + " volatile uchar bfs_idle[BFS_MAXPROCS]; /* set when all input queues are empty */", + "#ifdef BFS_DISK", + " volatile uchar bfs_out_cnt[BFS_MAXPROCS]; /* set when core writes a state */", + "#endif", + "", + "#ifdef BFS_QSZ", + " #define BFS_NORECYCLE", + " #if BFS_QSZ<=0", + " #error BFS_QSZ must be positive", + " #endif", + " #ifdef BFS_FIFO", + " #error BFS_QSZ cannot be combined with BFS_FIFO", + " #endif", + " #ifdef BFS_DISK", + " #error BFS_QSZ cannot be combined with BFS_DISK", + " #endif", + " volatile BFS_Slot bfsq[BFS_GEN][BFS_MAXPROCS][BFS_MAXPROCS][BFS_QSZ];", + " volatile uint bfs_ix[BFS_GEN][BFS_MAXPROCS][BFS_MAXPROCS];", + "#else", + " volatile BFS_Slot *head[BFS_GEN][BFS_MAXPROCS][BFS_MAXPROCS];", + "#endif", + "", + "#ifdef BFS_FIFO", + " volatile BFS_Slot *tail[BFS_GEN][BFS_MAXPROCS][BFS_MAXPROCS];", + " volatile BFS_Slot *dels[BFS_GEN][BFS_MAXPROCS][BFS_MAXPROCS];", + "#endif", + "#ifdef BFS_LOGMEM", + " volatile ulong logmem[1024];", + "#endif", + " volatile ulong mem_left;", + " volatile uchar *allocator; /* start of shared heap, must be last */", + "};", + "", + "enum bfs_types { EMPTY = 0, STATE, DELETED };", + "", + "extern volatile uchar *bfs_get_shared_mem(key_t, size_t);", + "extern BFS_Slot * bfs_new_slot(BFS_Trail *);", + "extern BFS_Slot * bfs_prep_slot(BFS_Trail *, BFS_Slot *);", + "extern BFS_Slot * bfs_next(void);", + "extern BFS_Slot * bfs_pack_state(Trail *, BFS_Trail *, int, BFS_Slot *);", + "extern SV_Hold * bfs_new_sv(int);", + "#if NRUNS>0", + "extern EV_Hold * bfs_new_sv_mask(int);", + "#endif", + "extern BFS_Trail * bfs_grab_trail(void);", + "extern BFS_Trail * bfs_unpack_state(BFS_Slot *);", + "extern int bfs_all_empty(void);", + "extern int bfs_all_idle(void);", + "extern int bfs_all_running(void);", + "extern int bfs_idle_and_empty(void);", + "extern size_t bfs_find_largest(key_t);", + "", + "extern void bfs_clear_locks(void);", + "extern void bfs_drop_shared_memory(void);", + "extern void bfs_explore_state(BFS_Slot *);", + "extern void bfs_initial_state(void);", + "extern void bfs_mark_done(int);", + "extern void bfs_printf(const char *fmt, ...);", + "extern void bfs_push_state(Trail *, BFS_Trail *, int);", + "extern void bfs_recycle(BFS_Slot *);", + "extern void bfs_release_trail(BFS_Trail *);", + "extern void bfs_run(void);", + "extern void bfs_setup_mem(void);", + "extern void bfs_setup(void);", + "extern void bfs_shutdown(const char *);", + "extern void bfs_statistics(void);", + "extern void bfs_store_state(Trail *, short);", + "extern void bfs_set_toggle(void);", + "extern void bfs_update(void);", + "", + "#ifdef MA", + " #error cannot combine -DMA with -DBFS_PAR", + " /* would require us to parallelize g_store */", + "#endif", + "#ifdef BCS", + " #error cannot combine -DBCS with -DBFS_PAR", + "#endif", + "#ifdef BFS_DISK", + " #ifdef BFS_FIFO", + " #error cannot combine BFS_DISK and BFS_FIFO", + " #endif", + " extern void bfs_disk_start(void);", + " extern void bfs_disk_stop(void);", + " extern void bfs_disk_out(void);", + " extern void bfs_disk_inp(void);", + " extern void bfs_disk_iclose(void);", + " extern void bfs_disk_oclose(void);", + " int bfs_out_fd[BFS_MAXPROCS];", + " int bfs_inp_fd[BFS_MAXPROCS];", + "#endif", + "", + "static BFS_shared *shared_memory;", + "#ifndef BFS_QSZ", + "static BFS_Slot *bfs_free_slot; /* local free list */", + "#endif", + "static BFS_Slot bfs_null;", + "static SV_Hold *bfs_svfree[VECTORSZ];", + "static uchar *bfs_heap; /* local pointer into heap */", + "static ulong bfs_left; /* local part of shared heap */", + "#if NRUNS>0", + "static void bfs_keep(EV_Hold *);", + "#endif", + "static long bfs_sent; /* nr msgs sent -- local to each process */", + "static long bfs_rcvd; /* nr msgs rcvd */", + "static long bfs_sleep_cnt; /* stats */", + "static long bfs_wcount;", + "static long bfs_gcount;", + "static ulong bfs_total_shared;", + "#ifdef BFS_STAGGER", + " static int bfs_stage_cnt = 0;", + " static void bfs_stagger_flush(void);", + "#endif", + "static int bfs_toggle; /* local variable, 0 or 1 */", + "static int bfs_qscan; /* scan input queues in order */", + "static ulong bfs_snapped;", + "static int shared_mem_id;", + "#ifndef NOREDUCE", + "static int bfs_nps; /* no preselection */", + "#endif", + "ulong bfs_punt; /* states dropped for lack of memory */", + "#if defined(VERBOSE) || defined(BFS_CHECK)", + "static const char *bfs_sname[] = {", + " \"EMPTY\", /* 0 */", + " \"STATE\", /* 1 */", + " \"STATE\", /* 2 = DELETED */", + " 0", + "};", + "#endif", + "static const char *bfs_lname[] = { /* match values defined in pangen2.c */", + " \"global lock\", /* BFS_GLOB */", + " \"ordinal\", /* BFS_ORD */", + " \"shared memory\", /* BFS_MEM */", + " \"print to stdout\", /* BFS_PRINT */", + " \"hashtable\", /* BFS_STATE */", + " 0", + "};", + "", + "static ulong bfs_count[DELETED+1]; /* indexed with bfs_types: EMPTY=0, STATE=1, DELETED=2 */", + "", + "static int bfs_keep_state;", + "", + "int Cores = 1;", + "int who_am_i = 0; /* root */", + "", + "#ifdef L_BOUND", + " int L_bound = L_BOUND;", + "#endif", + "", + "#ifdef BFS_CHECK", + "void", + "bfs_dump_now(char *s)", + "{ int i; char *p = (char *) &now;", + "", + " e_critical(BFS_PRINT);", + " printf(\"%%s\\t\", s);", + " printf(\"%%3lu: \", vsize);", + " for (i = 0; i < vsize; i++)", + " { printf(\"%%3d \", *p++);", + " }", + " printf(\" %%s\\noffsets:\\t\", s);", + " for (i = 0; i < now._nr_pr; i++)", + " { printf(\"%%3d \", proc_offset[i]);", + " }", + " printf(\"\\n\");", + " x_critical(BFS_PRINT);", + "}", + "", + "void", + "view_state(char *s) /* debugging */", + "{ int i;", + " char *p;", + " e_critical(BFS_PRINT);", + " printf(\"cpu%%02d %%s: \", who_am_i, s);", + " p = (char *)&now;", + " for (i = 0; i < vsize; i++)", + " printf(\"%%3d, \", *p++);", + " printf(\"\\n\"); fflush(stdout);", + " x_critical(BFS_PRINT);", + "}", + "#endif", + "", + "void", + "bfs_main(int ncores, int cycles)", + "{", + " if (cycles)", + " { fprintf(stderr, \"pan: cycle detection is not supported in this mode\\n\");", + " exit(1);", + " }", + "", + " if (ncores == 0) /* i.e., find out */", + " { FILE *fd;", + " char buf[512];", + " if ((fd = fopen(\"/proc/cpuinfo\", \"r\")) == NULL)", + " { /* cannot tell */", + " ncores = Cores; /* use the default */", + " } else", + " { while (fgets(buf, sizeof(buf), fd))", + " { if (strncmp(buf, \"processor\", strlen(\"processor\")) == 0)", + " { ncores++;", + " } }", + " fclose(fd);", + " ncores--;", + " if (verbose)", + " { printf(\"pan: %%d available cores\\n\", ncores+1);", + " } } }", + " if (ncores >= BFS_MAXPROCS)", + " { Cores = BFS_MAXPROCS-1; /* why -1? */", + " } else if (ncores < 1)", + " { Cores = 1;", + " } else", + " { Cores = ncores;", + " }", + " printf(\"pan: using %%d core%%s\\n\", Cores, (Cores>1)?\"s\":\"\");", + " fflush(stdout);", + "#ifdef BFS_DISK", + " bfs_disk_start();", /* create .spin */ + "#endif", + " bfs_setup(); /* shared memory segments and fork */", + " bfs_run();", + " if (who_am_i == 0)", + " { stop_timer(0);", + " }", + " bfs_statistics();", + " bfs_mark_done(1);", + " if (who_am_i == 0)", + " { report_time();", + "#ifdef BFS_DISK", + " bfs_disk_stop();", + "#endif", + " }", + "#ifdef C_EXIT", + " C_EXIT; /* trust that it defines a fct */", + "#endif", + " bfs_drop_shared_memory();", + " exit(0);", + "}", + "", + "void", + "bfs_setup_mem(void)", + "{ size_t n;", + " key_t key;", + "#ifdef BFS_FIFO", + " bfs_null.type = EMPTY;", + "#endif", + " ntrpt = (Trail *) emalloc(sizeof(Trail));", /* just once */ + "", + " if ((key = ftok(\".\", (int) 'L')) == -1)", + " { perror(\"ftok shared memory\");", + " exit(1);", + " }", + " n = bfs_find_largest(key);", + " bfs_total_shared = (ulong) n;", + "", + " shared_memory = (BFS_shared *) bfs_get_shared_mem(key, n); /* root */", + " shared_memory->allocator = (uchar *) shared_memory + sizeof(BFS_shared);", + " shared_memory->mem_left = (ulong) (n - sizeof(BFS_shared));", + "}", + "", + "ulong bfs_LowLim;", + "#ifndef BFS_RESERVE", + " #define BFS_RESERVE 5", + /* keep memory on global heap in reserve for first few cores */ + /* that run out of their local allocation of shared mem */ + /* 1~50 percent, 2~30 percent, 5~20 percent, >Cores=none */ + "#else", + " #if BFS_RESERVE<1", + " #error BFS_RESERVE must be at least 1", + " #endif", + "#endif", + "", + "void", + "bfs_setup(void) /* executed by root */", + "{ int i, j;", + " ulong n; /* share of shared memory allocated to each core */", + "", + " n = shared_memory->mem_left / (Cores + Cores/(BFS_RESERVE)); /* keep some reserve */", + "", + " if ((n%%sizeof(void *)) != 0)", + " { n -= (n%%sizeof(void *)); /* align, without exceeding total */", + " }", + " for (i = 0; i < Cores-1; i++)", + " { j = fork();", + " if (j == -1)", + " { bfs_printf(\"fork failed\\n\");", + " exit(1);", + " }", + " if (j == 0)", + " { who_am_i = i+1; /* 1..Cores-1 */", + " break;", + " } }", + "", + " e_critical(BFS_MEM);", + " bfs_heap = (uchar *) shared_memory->allocator;", + " shared_memory->allocator += n;", + " shared_memory->mem_left -= n;", + " x_critical(BFS_MEM);", + "", + " bfs_left = n;", + " bfs_runs = 1;", + " bfs_LowLim = n / (2 * (ulong) Cores);", /* 50% */ + "}", + "", + "void", + "bfs_run(void)", + "{ BFS_Slot *v;", + "", + "#ifdef BFS_DISK", + " bfs_disk_out();", /* create outqs */ + "#endif", + " if (who_am_i == 0)", + " { bfs_initial_state();", + " }", + "#ifdef BFS_DISK", + " #ifdef BFS_STAGGER", + " bfs_stagger_flush();", + " #endif", + " bfs_disk_oclose();", /* sync and close outqs */ + "#endif", + "#ifdef BFS_FIFO", + " static int i_count;", + "#endif", + "", + " srand(s_rand+HASH_NR);", + " bfs_qscan = 0;", + " bfs_toggle = 1 - bfs_toggle; /* after initial state */", + " e_critical(BFS_GLOB);", + " shared_memory->started++;", + " x_critical(BFS_GLOB);", + "", + " while (shared_memory->started != Cores) /* wait for all cores to connect */", + " { usleep(1);", + " }", + "", + "#ifdef BFS_DISK", + " bfs_disk_out();", + " bfs_disk_inp();", + "#endif", + "", + " start_timer();", + " while (shared_memory->quit == 0)", + " { v = bfs_next(); /* get next message from current generation */", + " if (v->s_data) /* v->type == STATE || v->type == DELETED */", + " { bfs_count[STATE]++;", + "#ifdef VERBOSE", + " bfs_printf(\"GOT STATE (depth %%d, nr %%u)\\n\",", + " v->s_data->t_info->o_tt, v->s_data->nr);", + "#endif", + " /* last resort: start dropping states when out of memory */", + " if (bfs_left > 1024 || shared_memory->mem_left > 1024)", + " { bfs_explore_state(v);", + " } else", + " { static int warned_loss = 0;", + " if (warned_loss == 0 && who_am_i == 0)", + " { warned_loss++;", + " bfs_printf(\"out of shared memory - losing states\\n\");", + " }", + " bfs_punt++;", + " }", + "#if !defined(BFS_FIFO) && !defined(BFS_NORECYCLE)", + " bfs_recycle(v);", + "#endif", + "#ifdef BFS_FIFO", + " i_count = 0;", + "#endif", + " } else", + " { bfs_count[EMPTY]++;", + "#if defined(BFS_FIFO) && defined(BFS_CHECK)", + " assert(v->type == EMPTY);", + "#endif", + "#ifdef BFS_FIFO", + " if (who_am_i == 0)", + " { if (bfs_idle_and_empty())", + " { if (i_count++ > 10)", + " { shared_memory->quit = 1;", + " }", + " else usleep(1);", + " }", + " } else if (!bfs_all_running())", + " { bfs_shutdown(\"early termination\");", + " }", + "#else", + " if (who_am_i == 0)", + " { if (bfs_all_idle()) /* wait for it */", + " { if (!bfs_all_empty()) /* more states to process */", + " { bfs_set_toggle();", + " goto do_toggle;", + " } else /* done */", + " { shared_memory->quit = 1; /* step 4 */", + " }", + " } else", + " { bfs_sleep_cnt++;", + " }", + " } else", + " { /* wait for quit or idle bit to be reset by root */", + " while (shared_memory->bfs_idle[who_am_i] == 1", + " && shared_memory->quit == 0)", + " { if (bfs_all_running())", + " { bfs_sleep_cnt++;", + " usleep(10); /* new 6.2.3 */", + " } else", + " { bfs_shutdown(\"early termination\");", + " /* no return */", + " } }", + "do_toggle: bfs_qscan = 0;", + "#ifdef BFS_DISK", + " bfs_disk_iclose();", + " bfs_disk_oclose();", + "#endif", + " bfs_toggle = 1 - bfs_toggle;", + "#ifdef BFS_DISK", + " bfs_disk_out();", + " bfs_disk_inp();", + "#endif", + " #ifdef BFS_CHECK", + " bfs_printf(\"toggle: recv from %%d, send to %%d\\n\",", + " bfs_toggle, 1 - bfs_toggle);", + " #endif", + " }", + "#endif", + " } }", + "#ifdef BFS_CHECK", + " bfs_printf(\"done, sent %%5ld recvd %%5ld punt %%5lu sleep: %%ld\\n\",", + " bfs_sent, bfs_rcvd, bfs_punt, bfs_sleep_cnt);", + "#endif", + "}", + "", + "void", + "bfs_report_mem(void) /* called from within wrapup() */", + "{", + " printf(\"%%9.3f total shared memory usage\\n\\n\",", + " ((double) bfs_total_shared - (double) bfs_left)/(1024.*1024.));", + "}", + "", + "void", + "bfs_statistics(void)", + "{", + " #ifdef VERBOSE", + " enum bfs_types i;", + " #endif", + " if (verbose)", + " bfs_printf(\"states sent %%7ld recvd %%7ld stored %%8g sleeps: %%4ld, %%4ld, %%ld\\n\",", + " bfs_sent, bfs_rcvd, nstates, bfs_wcount, bfs_gcount, bfs_sleep_cnt);", + " if (0) bfs_printf(\"states punted %%7lu\\n\", bfs_punt);", + " #ifdef VERBOSE", + " for (i = EMPTY; i <= DELETED; i++)", + " { if (bfs_count[i] > 0)", + " { bfs_printf(\"%%6s %%8lu\\n\",", + " bfs_sname[i], bfs_count[i]);", + " } }", + " #endif", + " bfs_update();", + "", + " if (who_am_i == 0 && shared_memory)", + " { int i; ulong count = 0L;", + " done = 1;", + "", + " e_critical(BFS_PRINT);", + " wrapup();", + " if (verbose)", + " { printf(\"\\nlock-wait counts:\\n\");", + " for (i = 0; i < BFS_STATE; i++)", + " printf(\"%%16s %%9lu\\n\",", + " bfs_lname[i], shared_memory->wait_count[i]);", + "#ifndef BITSTATE", + " for (i = BFS_STATE; i < BFS_MAXLOCKS; i++)", + " { if (0)", + " printf(\" [%%6d] %%9lu\\n\",", + " i, shared_memory->wait_count[i]);", + " count += shared_memory->wait_count[i];", + " }", + " printf(\"%%16s %%9lu (avg per region)\\n\",", + " bfs_lname[BFS_STATE], count/(BFS_MAXLOCKS - BFS_STATE));", + "#endif", + " }", + " fflush(stdout);", + " x_critical(BFS_PRINT);", + " }", + "}", + "", + "void", + "bfs_snapshot(void)", + "{ clock_t stop_time;", + " double delta_time;", + " struct tms stop_tm;", + " volatile BFS_data *s;", + "", + " e_critical(BFS_PRINT);", + " printf(\"cpu%%02d Depth= %%7lu States= %%8.3g Transitions= %%8.3g \",", + " who_am_i, mreached, nstates, nstates+truncs);", + " printf(\"Memory= %%9.3f\\t\", memcnt/1048576.);", + " printf(\"SharedMLeft= %%4lu \", bfs_left/1048576);", + " stop_time = times(&stop_tm);", + " delta_time = ((double) (stop_time - start_time))/((double) sysconf(_SC_CLK_TCK));", + " if (delta_time > 0.01)", + " { printf(\"t= %%6.3g R= %%6.0g\\n\", delta_time, nstates/delta_time);", + " } else", + " { printf(\"t= %%6.3g R= %%6.0g\\n\", 0., 0.);", + " }", + " fflush(stdout);", + " x_critical(BFS_PRINT);", + "", + " s = &shared_memory->bfs_data[who_am_i];", + " s->mreached = (ulong) mreached;", + " s->vsize = (ulong) vsize;", + " s->errors = (int) errors;", + " s->memcnt = (double) memcnt;", + " s->nstates = (double) nstates;", + " s->nlinks = (double) nlinks;", + " s->truncs = (double) truncs;", + " s->memory_left = (ulong) bfs_left;", + " s->punted = (ulong) bfs_punt;", + " bfs_snapped++; /* for bfs_best */", + "}", + "", + "void", + "bfs_shutdown(const char *s)", + "{", + " bfs_clear_locks(); /* in case we interrupted at a bad point */", + " if (!strstr(s, \"early \") || verbose)", + " { bfs_printf(\"stop (%%s)\\n\", s);", + " }", + " bfs_update();", + " if (who_am_i == 0)", + " { wrapup();", + "#ifdef BFS_DISK", + " bfs_disk_stop();", + "#endif", + " }", + " bfs_mark_done(2);", + " pan_exit(2);", + "}", + "", + "SV_Hold *bfs_free_hold;", + "", + "SV_Hold *", + "bfs_get_hold(void)", + "{ SV_Hold *x;", + " if (bfs_free_hold)", + " { x = bfs_free_hold;", + " bfs_free_hold = bfs_free_hold->nxt;", + " } else", + " { x = (SV_Hold *) sh_malloc((ulong) sizeof(SV_Hold));", + " }", + " return x;", + "}", + "", + "BFS_Trail *", + "bfs_unpack_state(BFS_Slot *n) /* called in bfs_explore_state */", + "{ BFS_Trail *otrpt;", + " BFS_State *bfs_t;", + " int vecsz;", + "", + " if (!n || !n->s_data || !n->s_data->t_info)", + " { bfs_Uerror(\"internal error\");", + " }", + " otrpt = (BFS_Trail *) ((BFS_State *) n->s_data)->t_info;", + "", + " trpt->ostate = otrpt->ostate;", + " trpt->st = otrpt->st;", + " trpt->o_tt = otrpt->o_tt;", + " trpt->pr = otrpt->pr;", + " trpt->tau = otrpt->tau;", + " trpt->o_pm = otrpt->o_pm;", + " if (trpt->ostate)", + " trpt->o_t = t_id_lkup[otrpt->t_id];", + "#if defined(C_States) && (HAS_TRACK==1)", + " c_revert((uchar *) &(now.c_state[0]));", + "#endif", + " if (trpt->o_pm & 4) /* rv succeeded */", + " { return (BFS_Trail *) 0; /* revisit not needed */", + " }", + "#ifndef NOREDUCE", + " bfs_nps = 0;", + "#endif", + " if (trpt->o_pm & 8) /* rv attempt failed */", + " { revrv++;", + " if (trpt->tau&8)", + " { trpt->tau &= ~8; /* break atomic */", + "#ifndef NOREDUCE", + " } else if (trpt->tau&32) /* void preselection */", + " { trpt->tau &= ~32;", + " bfs_nps = 1; /* no preselection in repeat */", + "#endif", + " } }", + " trpt->o_pm &= ~(4|8);", + " if (trpt->o_tt > mreached)", + " { static ulong nr = 0L, nc;", + " mreached = trpt->o_tt;", + " nc = (long) nstates/FREQ;", + " if (nc > nr)", + " { nr = nc;", + " bfs_snapshot();", + " } }", + " depth = trpt->o_tt;", + " if (depth >= maxdepth)", + " {", + "#if SYNC", + " if (boq != -1)", + " { BFS_Trail *x = (BFS_Trail *) trpt->ostate;", + " if (x) x->o_pm |= 4; /* rv not failing */", + " }", + "#endif", + " truncs++;", + " if (!warned)", + " { warned = 1;", + " bfs_printf(\"error: max search depth too small\\n\");", + " }", + " if (bounded)", + " { bfs_uerror(\"depth limit reached\");", + " }", + " return (BFS_Trail *) 0;", + " }", + "", + " bfs_t = n->s_data;", + "#if NRUNS>0", + " vsize = bfs_t->omask->sz;", + "#else", + " vsize = ((State *) (bfs_t->osv))->_vsz;", + "#endif", + "#if SYNC", + " boq = bfs_t->boq;", + "#endif", + "", + "#if defined(Q_PROVISO) && !defined(BITSTATE) && defined(FULLSTACK)", + " #ifdef USE_TDH", + " if (((uchar *)(bfs_t->lstate))) /* if BFS_INQ is set */", + " { *((uchar *) bfs_t->lstate) = 0; /* turn it off */", + " }", + " #else", + " if (bfs_t->lstate) /* bfs_par */", + " { bfs_t->lstate->tagged = 0; /* bfs_par state removed from q */", + " }", + " #endif", + "#endif", + " memcpy((char *) &now, (uchar *) bfs_t->osv, vsize);", + "#if !defined(NOCOMP) && !defined(HC) && NRUNS>0", + " Mask = (uchar *) bfs_t->omask->sv; /* in shared memory */", + "#endif", + "#ifdef BFS_CHECK", + " if (0) bfs_dump_now(\"got1\");", + "#endif", + "#ifdef TRIX", + " re_populate();", + "#else", + " #if NRUNS>0", + " if (now._nr_pr > 0)", + " {", + " #if VECTORSZ>32000", + " proc_offset = (int *) bfs_t->omask->po;", + " #else", + " proc_offset = (short *) bfs_t->omask->po;", + " #endif", + " proc_skip = (uchar *) bfs_t->omask->ps;", + " }", + " if (now._nr_qs > 0)", + " {", + " #if VECTORSZ>32000", + " q_offset = (int *) bfs_t->omask->qo;", + " #else", + " q_offset = (short *) bfs_t->omask->qo;", + " #endif", + " q_skip = (uchar *) bfs_t->omask->qs;", + " }", + " #endif", + "#endif", + " vecsz = ((State *) bfs_t->osv)->_vsz;", + "#ifdef BFS_CHECK", + " assert(vecsz > 0 && vecsz < VECTORSZ);", + "#endif", + " { SV_Hold *x = bfs_get_hold();", + " x->sv = bfs_t->osv;", + " x->nxt = bfs_svfree[vecsz];", + " bfs_svfree[vecsz] = x;", + " bfs_t->osv = (State *) 0;", + " }", + "#if NRUNS>0", + " bfs_keep(bfs_t->omask);", + "#endif", + "", + "#ifdef BFS_CHECK", + " if (0) bfs_dump_now(\"got2\");", + " if (0) view_state(\"after\");", + "#endif", + " return (BFS_Trail *) bfs_t->t_info;", + "}", + "void", + "bfs_initial_state(void)", + "{", + "#ifdef BFS_CHECK", + " assert(trpt != NULL);", + "#endif", + " trpt->ostate = (H_el *) 0;", + " trpt->o_tt = -1;", + " trpt->tau = 0;", + "#ifdef VERI", + " trpt->tau |= 4; /* claim moves first */", + "#endif", + " bfs_store_state(trpt, boq); /* initial state : bfs_lib.c */", + "}", + "", + "#ifdef BITSTATE", + " #define bfs_do_store(v, n) b_store(v, n)", + "#else", + " #ifdef USE_TDH", + " #define bfs_do_store(v, n) o_store(v, n)", + " #else", + " #define bfs_do_store(v, n) h_store(v, n)", + " #endif", + "#endif", + "", + "#ifdef BFS_SEP_HASH", + "int", + "bfs_seen_before(void)", + "{ /* cannot set trpt->tau |= 64 to mark successors outside stack */", + " /* since the check is done remotely and the trpt value is gone */", + " #ifdef VERI", + " if (!trpt->ostate /* initial state */", + " || ((trpt->tau&4) /* starting claim moves(s) */", + " && !(((BFS_Trail *)trpt->ostate)->tau&4))) /* prev move: prog */", + " { return 0; /* claim move: mid-state not stored */", + " } /* else */", + " #endif", + " if (!bfs_do_store((char *)&now, vsize)) /* sep_hash */", + " { nstates++; /* local count */", + " return 0; /* new state */", + " }", + " #ifdef BFS_CHECK", + " bfs_printf(\"seen before\\n\");", + " #endif", + " truncs++;", + " return 1; /* old state */", + "}", + "#endif", + "", + "void", + "bfs_explore_state(BFS_Slot *v) /* generate all successors of v */", + "{ BFS_Trail *otrpt;", + " Trans *t;", + "#ifdef HAS_UNLESS", + " int E_state;", + "#endif", + " int tt;", + " short II, To = BASE, From = (short) (now._nr_pr-1);", + " short oboq = boq;", + " uchar _n, _m, ot;", + "", + " memset(ntrpt, 0, sizeof(Trail));", + " otrpt = bfs_unpack_state(v); /* BFS_Trail */", + "", + " if (!otrpt) { return; } /* e.g., depth limit reached */", + "#ifdef L_BOUND", + " #if defined(VERBOSE)", + " bfs_printf(\"Unpacked state with l_bound %%d -- sds %%p\\n\",", + " now._l_bnd, now._l_sds);", + " #endif", + "#endif", + "", + "#if defined(C_States) && (HAS_TRACK==1)", + " c_revert((uchar *) &(now.c_state[0]));", + "#endif", + "", + "#ifdef BFS_SEP_HASH", + " if (bfs_seen_before()) return;", + "#endif", + "", + "#ifdef VERI", /* could move to just before store_state */ + " if (now._nr_pr == 0 /* claim terminated */", + " || stopstate[((Pclaim *)pptr(0))->_t][((Pclaim *)pptr(0))->_p])", + " { bfs_uerror(\"end state in claim reached\");", + " }", + "#endif", + " trpt->tau &= ~1; /* timeout off */", + "#ifdef VERI", + " if (trpt->tau&4) /* claim move */", + " { trpt->tau |= (otrpt->tau)&1; /* inherit from prog move */", + " From = To = 0; /* claim */", + " goto Repeat_two;", + " }", + "#endif", + "#ifndef NOREDUCE", + " if (boq == -1 && !(trpt->tau&8) && bfs_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)", + " { t = trans[ot][tt];", + " if (t->qu[0] != 0)", + " { if (!q_cond(II, t))", + " continue;", + " }", + " From = To = II;", + " trpt->tau |= 32; /* preselect marker */", + " #ifdef VERBOSE", + " bfs_printf(\"%%3ld: proc %%d PreSelected (tau=%%d)\\n\", ", + " depth, II, trpt->tau);", + " #endif", + " goto Repeat_two;", + " } }", + " trpt->tau &= ~32;", + "#endif", + "", + "Repeat_one:", + " if (trpt->tau&8)", + " { From = To = (short ) trpt->pr; /* atomic */", + " } else", + " { From = now._nr_pr-1;", + " To = BASE;", + " }", + "#if defined(VERI) || !defined(NOREDUCE) || defined(ETIM)", + "Repeat_two: /* MainLoop */", + "#endif", + " _n = _m = 0;", + " for (II = From; II >= To; II -= 1) /* all processes */", + " {", + "#ifdef BFS_CHECK", + " bfs_printf(\"proc %%d (%%d - %%d)\\n\", II, From, To);", + "#endif", + "#if SYNC ", + " if (boq != -1 && trpt->pr == II)", + " { continue; /* no rendezvous with same proc */", + " }", + "#endif", + " this = pptr(II);", + " tt = (int) ((P0 *)this)->_p;", + " ot = (uchar) ((P0 *)this)->_t;", + " 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_PRIORITY", + " if (!highest_priority(((P0 *)this)->_pid, II, t))", + " { continue;", + " }", + "#else", + " #ifdef HAS_PROVIDED", + " if (!provided(II, ot, tt, t))", + " { continue;", + " }", + " #endif", + "#endif", + "#ifdef HAS_UNLESS", + " E_state = 0;", + "#endif", + " for (t = trans[ot][tt]; t; t = t->nxt) /* all process transitions */", + " {", + "#ifdef BFS_CHECK", + " assert(t_id_lkup[t->t_id] == t); /* for reverse lookup in bfs_unpack_state */", + "#endif", + "#ifdef VERBOSE", + " if (0) bfs_printf(\"\\tproc %%d tr %%d\\n\", II, t->forw);", + "#endif", + "#ifdef HAS_UNLESS", + " if (E_state > 0", + " && E_state != t->e_trans)", + " break;", + "#endif", + " /* trpt->o_t = */ 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 VERBOSE", + " e_critical(BFS_PRINT);", + " printf(\"%%3ld: 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);", + " x_critical(BFS_PRINT);", + "#endif", + "#ifdef HAS_UNLESS", + " E_state = t->e_trans;", + " #if SYNC>0", + " if (t->e_trans > 0 && boq != -1)", + " { fprintf(efd, \"error: rendezvous stmnt in the escape clause\\n\");", + " fprintf(efd, \" of unless stmnt not compatible with -DBFS\\n\");", + " pan_exit(1);", + " }", + " #endif", + "#endif", + " if (t->st > 0)", + " { ((P0 *)this)->_p = t->st;", + " }", + " /* use the ostate ptr, with type *H_el, to temporarily store *BFS_Trail */", + "#ifdef BFS_NOTRAIL", + " ntrpt->ostate = (H_el *) 0; /* no error-traces in this mode */", + "#else", + " ntrpt->ostate = (H_el *) otrpt; /* parent stackframe */", + "#endif", + " /* ntrpt->st = tt; * was already set above */", + "", + " if (boq == -1 && (t->atom&2)) /* atomic */", + " { ntrpt->tau = 8; /* record for next move */", + " } else", + " { ntrpt->tau = 0; /* no timeout or preselect etc */", + " }", + "#ifdef VERI", + " ntrpt->tau |= trpt->tau&4; /* if claim, inherit */", + " if (boq == -1 && !(ntrpt->tau&8)) /* unless rv or atomic */", + " { if (ntrpt->tau&4) /* claim */", + " { ntrpt->tau &= ~4; /* switch to prog */", + " } else", + " { ntrpt->tau |= 4; /* switch to claim */", + " } }", + "#endif", + "#ifdef L_BOUND", + " { uchar obnd = now._l_bnd;", + " uchar *os = now._l_sds;", + " #ifdef VERBOSE", + " bfs_printf(\"saving bound %%d -- sds %%p\\n\", obnd, (void *) os);", + " #endif", + "#endif", + "", + " bfs_store_state(ntrpt, oboq);", + "#ifdef EVENT_TRACE", + " now._event = trpt->o_event;", + "#endif", + " /* undo move and generate other successor states */", + " trpt++; /* this is where ovals and ipt are set */", + " do_reverse(t, II, _m); /* restore now. */", + "#ifdef L_BOUND", + " #ifdef VERBOSE", + " bfs_printf(\"restoring bound %%d -- sds %%p\\n\", obnd, (void *) os);", + " #endif", + " now._l_bnd = obnd;", + " now._l_sds = os;", + " }", + "#endif", + " trpt--;", + "#ifdef VERBOSE", + " e_critical(BFS_PRINT);", + " printf(\"%%3ld: 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, 0);", + " printf(\"tau=%%d,%%d]\\n\", trpt->tau, (trpt-1)->tau);", + " x_critical(BFS_PRINT);", + "#endif", + " reached[ot][t->st] = 1;", + " reached[ot][tt] = 1;", + "", + " ((P0 *)this)->_p = tt;", + " _n |= _m;", + " } }", + "#ifdef VERBOSE", + " bfs_printf(\"done _n = %%d\\n\", _n);", + "#endif", + "", + "#ifndef NOREDUCE", + " /* preselected - no succ definitely outside stack */", + " if ((trpt->tau&32) && !(trpt->tau&64))", + " { From = now._nr_pr-1; To = BASE;", + " #ifdef VERBOSE", + " bfs_printf(\"%%3ld: 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 Repeat_two;", + " }", + " trpt->tau &= ~(32|64);", + "#endif", + " if (_n == 0", + "#ifdef VERI", + " && !(trpt->tau&4)", + "#endif", + " )", + " { /* no successor states generated */", + " if (boq != -1) /* was rv move */", + " { BFS_Trail *x = (BFS_Trail *) trpt->ostate; /* pre-rv state */", + " if (x && ((x->tau&8) || (x->tau&32))) /* break atomic or preselect */", + " { x->o_pm |= 8; /* mark failure */", + " this = pptr(otrpt->pr);", + " ((P0 *) this)->_p = otrpt->st; /* reset state */", + " unsend(boq); /* retract rv offer */", + " boq = -1;", + "#ifdef VERBOSE", + " printf(\"repush state\\n\");", + "#endif", + " bfs_push_state(NULL, x, x->o_tt); /* repush rv fail */", + " } /* else the rv need not be retried */", + " } else if (now._nr_pr > BASE) /* possible deadlock */", + " { if ((trpt->tau&8)) /* atomic step blocked */", + " { trpt->tau &= ~(1|8); /* 1=timeout, 8=atomic */", + " goto Repeat_one;", + " }", + "#ifdef ETIM", + " /* if timeouts were used in the model */", + " if (!(trpt->tau&1))", + " { trpt->tau |= 1; /* enable timeout */", + " goto Repeat_two;", + " }", + "#endif", + " if (!noends && !endstate())", + " { bfs_uerror(\"invalid end state.\");", + " }", + " }", + "#ifdef VERI", + " else /* boq == -1 && now._nr_pr == BASE && trpt->tau != 4 */", + " { trpt->tau |= 4; /* switch to claim for stutter moves */", + " #ifdef VERBOSE", + " printf(\"%%3ld: proc -1 exec -1, (stutter move)\\n\", depth, II);", + " #endif", + " bfs_store_state(trpt, boq);", /* doesn't store it but queues it */ + " #ifdef VERBOSE", + " printf(\"%%3ld: proc -1 reverses -1, (stutter move)\\n\", depth, II);", + " #endif", + " trpt->tau &= ~4; /* undo, probably not needed */", + " }", + "#endif", + " }", + "#ifdef BFS_NOTRAIL", + " bfs_release_trail(otrpt);", + "#endif", + "}", + "#if !defined(BFS_FIFO) && !defined(BFS_NORECYCLE)", + "void", + "bfs_recycle(BFS_Slot *n)", + "{", + " #ifdef BFS_CHECK", + " assert(n != &bfs_null);", + " #endif", + " n->nxt = bfs_free_slot;", + " bfs_free_slot = n;", + "", + " #ifdef BFS_CHECK", + " bfs_printf(\"recycles %%s -- %%p\\n\",", + " n->s_data?\"STATE\":\"EMPTY\", (void *) n);", + " #endif", + "}", + "#endif", + "#ifdef BFS_FIFO", + "int", + "bfs_empty(int p)", /* return Cores if all empty or index of first non-empty q of p */ + "{ int i;", + " const int dst = 0;", + " for (i = 0; i < Cores; i++)", + " { if (shared_memory->head[dst][p][i] != (BFS_Slot *) 0)", + " {", + " volatile BFS_Slot *x = shared_memory->head[dst][p][i];", + " while (x && x->type == DELETED)", + " { x = x->nxt;", + " }", + " if (!x)", + " { continue;", + " }", + " if (p == who_am_i)", + " { shared_memory->head[dst][p][i] = x;", + " }", + " #ifdef BFS_CHECK", + " bfs_printf(\"input q [%%d][%%d][%%d] !empty\\n\",", + " dst, p, i);", + " #endif", + " return i;", + " } }", + " #ifdef BFS_CHECK", + " bfs_printf(\"all input qs [%%d][%%d][0..max] empty\\n\",", + " dst, p);", + " #endif ", + " return Cores;", + "}", + "#endif", + "#ifdef BFS_DISK", + "void", + "bfs_ewrite(int fd, const void *p, size_t count)", + "{", + " if (write(fd, p, count) != count)", + " { perror(\"diskwrite\");", + " Uerror(\"aborting\");", + " }", + "}", + "", + "void", + "bfs_eread(int fd, void *p, size_t count)", + "{", + " if (read(fd, p, count) != count)", + " { perror(\"diskread\");", + " Uerror(\"aborting\");", + " }", + "}", + "", + "void", + "bfs_sink_disk(int who_are_you, BFS_Slot *n)", + "{ SV_Hold *x;", + "#ifdef VERBOSE", + " bfs_printf(\"sink_disk -> %%d\\n\", who_are_you);", + "#endif", + " bfs_ewrite(bfs_out_fd[who_are_you], (const void *) n->s_data->t_info, sizeof(BFS_Trail));", + " bfs_ewrite(bfs_out_fd[who_are_you], (const void *) &vsize, sizeof(ulong));", + " bfs_ewrite(bfs_out_fd[who_are_you], &now, vsize);", + "", + " bfs_release_trail(n->s_data->t_info);", + " n->s_data->t_info = (BFS_Trail *) 0;", + "", + "#if NRUNS>0", + " bfs_ewrite(bfs_out_fd[who_are_you], (const void *) &(n->s_data->omask), sizeof(EV_Hold *));", + "#endif", + "#ifdef Q_PROVISO", + " bfs_ewrite(bfs_out_fd[who_are_you], (const void *) &(n->s_data->lstate), sizeof(H_el *));", + "#endif", + "#if SYNC>0", + " bfs_ewrite(bfs_out_fd[who_are_you], (const void *) &(n->s_data->boq), sizeof(short));", + "#endif", + "#if VERBOSE", + " bfs_ewrite(bfs_out_fd[who_are_you], (const void *) &(n->s_data->nr), sizeof(ulong));", + "#endif", + " shared_memory->bfs_out_cnt[who_am_i] = 1;", /* wrote at least one state */ + "}", + "void", + "bfs_source_disk(int fd, volatile BFS_Slot *n)", + "{ ulong nb; /* local temporary */", + " SV_Hold *x;", + "#ifdef VERBOSE", + " bfs_printf(\"source_disk <- %%d\\n\", who_am_i);", + "#endif", + " n->s_data->t_info = bfs_grab_trail();", + " bfs_eread(fd, (void *) n->s_data->t_info, sizeof(BFS_Trail));", + " bfs_eread(fd, (void *) &nb, sizeof(ulong));", + "", + " x = bfs_new_sv(nb); /* space for osv isn't already allocated */", + " n->s_data->osv = x->sv;", + " x->sv = (State *) 0;", + " x->nxt = bfs_free_hold;", + " bfs_free_hold = x;", + "", + " bfs_eread(fd, (void *) n->s_data->osv, (size_t) nb);", + "#if NRUNS>0", + " bfs_eread(fd, (void *) &(n->s_data->omask), sizeof(EV_Hold *));", + "#endif", + "#ifdef Q_PROVISO", + " bfs_eread(fd, (void *) &(n->s_data->lstate), sizeof(H_el *));", + "#endif", + "#if SYNC>0", + " bfs_eread(fd, (void *) &(n->s_data->boq), sizeof(short));", + "#endif", + "#if VERBOSE", + " bfs_eread(fd, (void *) &(n->s_data->nr), sizeof(ulong));", + "#endif", + "}", + "#endif", + "", + "#ifndef BFS_QSZ", + " #ifdef BFS_STAGGER", + "static BFS_Slot *bfs_stage[BFS_STAGGER];", + "", + "static void", + "bfs_stagger_flush(void)", + "{ int i, who_are_you;", + " int dst = 1 - bfs_toggle;", + " BFS_Slot *n;", + " who_are_you = (rand()%%Cores);", /* important: all to the same cpu, but reversed */ + " for (i = bfs_stage_cnt-1; i >= 0; i--)", + " { n = bfs_stage[i];", + " #ifdef BFS_DISK", + " bfs_sink_disk(who_are_you, n);", + " bfs_stage[i] = (BFS_Slot *) 0;", + " #endif", + " n->nxt = (BFS_Slot *) shared_memory->head[dst][who_are_you][who_am_i];", + " shared_memory->head[dst][who_are_you][who_am_i] = n;", + " /* bfs_sent++; */", + " }", + " #ifdef VERBOSE", + " bfs_printf(\"stagger flush %%d states to %%d\\n\",", + " bfs_stage_cnt, who_are_you);", + " #endif", + " bfs_stage_cnt = 0;", + "}", + "", + "void", + "bfs_stagger_add(BFS_Slot *n)", + "{", + " if (bfs_stage_cnt == BFS_STAGGER)", + " { bfs_stagger_flush();", + " }", + " bfs_stage[bfs_stage_cnt++] = n;", + "}", + " #endif", + "#endif", + "", + "void", + "bfs_push_state(Trail *x, BFS_Trail *y, int tt)", + "{ int who_are_you;", + "#ifdef BFS_FIFO", + " const int dst = 0;", + "#else", + " int dst = 1 - bfs_toggle;", + "#endif", + "#ifdef BFS_QSZ", + " uint z;", + " if (bfs_keep_state > 0)", + " { who_are_you = bfs_keep_state - 1;", + " } else", + " { who_are_you = (rand()%%Cores);", + " }", + " z = shared_memory->bfs_ix[dst][who_are_you][who_am_i];", + " if (z >= BFS_QSZ)", + " { static int warned_qloss = 0;", + " if (warned_qloss == 0 && who_am_i == 0)", + " { warned_qloss++;", + " bfs_printf(\"BFS_QSZ too small - losing states\\n\");", + " }", + " bfs_punt++;", + " return;", + " }", + " shared_memory->bfs_ix[dst][who_are_you][who_am_i] = z+1;", + " BFS_Slot *n = bfs_pack_state(x, y, tt, bfs_prep_slot(y, ", + " (BFS_Slot *) &(shared_memory->bfsq[dst][who_are_you][who_am_i][z])));", + "#else", + " BFS_Slot *n = bfs_pack_state(x, y, tt, bfs_new_slot(y));", + "", + " #ifdef BFS_GREEDY", + " who_are_you = who_am_i; /* for testing only */", + " #else", + " if (bfs_keep_state > 0)", + " { who_are_you = bfs_keep_state - 1;", + " } else", + " {", + " #ifdef BFS_STAGGER", + " who_are_you = -1;", + " bfs_stagger_add(n);", + " goto done;", + " #else", + " who_are_you = (rand()%%Cores);", + " #endif", + " }", + " #endif", + " #ifdef BFS_FIFO", + " if (!shared_memory->tail[dst][who_are_you][who_am_i])", + " { shared_memory->dels[dst][who_are_you][who_am_i] =", + " shared_memory->tail[dst][who_are_you][who_am_i] =", + " shared_memory->head[dst][who_are_you][who_am_i] = n;", + " } else", + " { shared_memory->tail[dst][who_are_you][who_am_i]->nxt = n;", + " shared_memory->tail[dst][who_are_you][who_am_i] = n;", + " }", + " shared_memory->bfs_idle[who_are_you] = 0;", + " #else", + " #ifdef BFS_DISK", + " bfs_sink_disk(who_are_you, n);", + " #endif", + " n->nxt = (BFS_Slot *) shared_memory->head[dst][who_are_you][who_am_i];", + " shared_memory->head[dst][who_are_you][who_am_i] = n;", + " #endif", + " #ifdef BFS_STAGGER", + "done:", + " #endif", + "#endif", /* BFS_QSZ */ + "#ifdef VERBOSE", + " bfs_printf(\"PUT STATE (depth %%ld, nr %%u) to %%d -- s_data: %%p\\n\",", + " tt, n->s_data->nr, who_are_you, n->s_data);", + "#endif", + " bfs_sent++;", + "}", + "", + "BFS_Slot *", + "bfs_next(void)", + "{ volatile BFS_Slot *n = &bfs_null;", + " #ifdef BFS_FIFO", + " const int src = 0;", + " bfs_qscan = bfs_empty(who_am_i);", + " #else", + " const int src = bfs_toggle;", + " #ifdef BFS_QSZ", + " while (bfs_qscan < Cores", + " && shared_memory->bfs_ix[src][who_am_i][bfs_qscan] == 0)", + " { bfs_qscan++;", + " }", + " #else", + " while (bfs_qscan < Cores", + " && shared_memory->head[src][who_am_i][bfs_qscan] == (BFS_Slot *) 0)", + " { bfs_qscan++;", + " }", + " #endif", + " #endif", + " if (bfs_qscan < Cores)", + " {", + " #ifdef BFS_FIFO", /* no wait for toggles */ + " shared_memory->bfs_idle[who_am_i] = 0;", + " for (n = shared_memory->head[src][who_am_i][bfs_qscan]; n; n = n->nxt)", + " { if (n->type != DELETED)", + " { break;", + " } }", + " #ifdef BFS_CHECK", + " assert(n && n->type == STATE); /* q cannot be empty */", + " #endif", + " if (n->nxt)", + " { shared_memory->head[src][who_am_i][bfs_qscan] = n->nxt;", + " }", /* else, do not remove it - yet - avoid empty queues */ + " n->type = DELETED;", + " #else", + " #ifdef BFS_QSZ", + " uint x = --shared_memory->bfs_ix[src][who_am_i][bfs_qscan];", + " n = &(shared_memory->bfsq[src][who_am_i][bfs_qscan][x]);", + " #else", + " n = shared_memory->head[src][who_am_i][bfs_qscan];", + " shared_memory->head[src][who_am_i][bfs_qscan] = n->nxt;", + " #if defined(BFS_FIFO) && defined(BFS_CHECK)", + " assert(n->type == STATE);", + " #endif", + " n->nxt = (BFS_Slot *) 0;", + " #endif", + " #ifdef BFS_DISK", + " /* the states actually show up in reverse order (FIFO iso LIFO) here */", + " /* but that doesnt really matter as long as the count is right */", + " bfs_source_disk(bfs_inp_fd[bfs_qscan], n); /* get the data */", + " #endif", + + " #endif", + " #ifdef BFS_CHECK", + " bfs_printf(\"rcv STATE from [%%d][%%d][%%d]\\n\",", + " src, who_am_i, bfs_qscan);", + " #endif", + " bfs_rcvd++;", + " } else", + " {", + " #if defined(BFS_STAGGER) && !defined(BFS_QSZ)", + " if (bfs_stage_cnt > 0)", + " { bfs_stagger_flush();", + " }", + " #endif", + " shared_memory->bfs_idle[who_am_i] = 1;", + " #if defined(BFS_FIFO) && defined(BFS_CHECK)", + " assert(n->type == EMPTY);", + " #endif", + " }", + " return (BFS_Slot *) n;", + "}", + "", + "int", + "bfs_all_empty(void)", + "{ int i;", + "#ifdef BFS_DISK", + " for (i = 0; i < Cores; i++)", + " { if (shared_memory->bfs_out_cnt[i] != 0)", + " {", + " #ifdef VERBOSE", + " bfs_printf(\"bfs_all_empty %%d not empty\\n\", i);", + " #endif", + " return 0;", + " } }", + "#else", + " int p;", + " #ifdef BFS_FIFO", + " const int dst = 0;", + " #else", + " int dst = 1 - bfs_toggle; /* next generation */", + " #endif", + " for (p = 0; p < Cores; p++)", + " for (i = 0; i < Cores; i++)", + " #ifdef BFS_QSZ", + " { if (shared_memory->bfs_ix[dst][p][i] > 0)", + " #else", + " { if (shared_memory->head[dst][p][i] != (BFS_Slot *) 0)", + " #endif", + " { return 0;", + " } }", + "#endif", + "#ifdef VERBOSE", + " bfs_printf(\"bfs_all_empty\\n\");", + "#endif", + " return 1;", + "}", + "", + "#ifdef BFS_FIFO", + "BFS_Slot *", + "bfs_sweep(void)", + "{ BFS_Slot *n;", + " int i;", + " for (i = 0; i < Cores; i++)", + " for (n = (BFS_Slot *) shared_memory->dels[0][who_am_i][i];", + " n && n != shared_memory->head[0][who_am_i][i];", + " n = n->nxt)", + " { if (n->type == DELETED && n->nxt)", + " { shared_memory->dels[0][who_am_i][i] = n->nxt;", + " n->nxt = (BFS_Slot *) 0;", + " return n;", + " } }", + " return (BFS_Slot *) sh_malloc((ulong) sizeof(BFS_Slot));", + "}", + "#endif", + "", + "typedef struct BFS_T_Hold BFS_T_Hold;", + "struct BFS_T_Hold {", + " volatile BFS_Trail *t;", + " BFS_T_Hold *nxt;", + "};", + "BFS_T_Hold *bfs_t_held, *bfs_t_free;", + "", + "BFS_Trail *", + "bfs_grab_trail(void)", /* call in bfs_source_disk and bfs_new_slot */ + "{ BFS_Trail *t;", + " BFS_T_Hold *h;", + "", + "#ifdef VERBOSE", + " bfs_printf(\"grab trail - bfs_t_held %%p\\n\", (void *) bfs_t_held);", + "#endif", + " if (bfs_t_held)", + " { h = bfs_t_held;", + " bfs_t_held = bfs_t_held->nxt;", + " t = (BFS_Trail *) h->t;", + " h->t = (BFS_Trail *) 0; /* make sure it cannot be reused */", + " h->nxt = bfs_t_free;", + " bfs_t_free = h;", + "", + " } else", + " { t = (BFS_Trail *) sh_malloc((ulong) sizeof(BFS_Trail));", + " }", + "#ifdef BFS_CHECK", + " assert(t);", + "#endif", + " t->ostate = (H_el *) 0;", + "#ifdef VERBOSE", + " bfs_printf(\"grab trail %%p\\n\", (void *) t);", + "#endif", + " return t;", + "}", + "", + "#if defined(BFS_DISK) || defined(BFS_NOTRAIL)", + "void", + "bfs_release_trail(BFS_Trail *t)", /* call in bfs_sink_disk (not bfs_recycle) */ + "{ BFS_T_Hold *h;", + " #ifdef BFS_CHECK", + " assert(t);", + " #endif", + " #ifdef VERBOSE", + " bfs_printf(\"release trail %%p\\n\", (void *) t);", + " #endif", + " if (bfs_t_free)", + " { h = bfs_t_free;", + " bfs_t_free = bfs_t_free->nxt;", + " } else", + " { h = (BFS_T_Hold *) emalloc(sizeof(BFS_T_Hold));", + " }", + " h->t = t;", + " h->nxt = bfs_t_held;", + " bfs_t_held = h;", + " #ifdef VERBOSE", + " bfs_printf(\"release trail - bfs_t_held %%p\\n\", (void *) bfs_t_held);", + " #endif", + "}", + "#endif", + "", + "#ifndef BFS_QSZ", + "BFS_Slot *", + "bfs_new_slot(BFS_Trail *f)", + "{ BFS_Slot *t;", + "", + "#ifdef BFS_FIFO", + " t = bfs_sweep();", + "#else", + " if (bfs_free_slot) /* local */", + " { t = bfs_free_slot;", + " bfs_free_slot = bfs_free_slot->nxt;", + " t->nxt = (BFS_Slot *) 0;", + " } else", + " { t = (BFS_Slot *) sh_malloc((ulong) sizeof(BFS_Slot));", + " }", + "#endif", + " if (t->s_data)", + " { memset(t->s_data, 0, sizeof(BFS_State));", + " } else", + " { t->s_data = (BFS_State *) sh_malloc((ulong) sizeof(BFS_State));", + " }", + "", + " /* we keep a ptr to the frame of parent states, which is */", + " /* used for reconstructing path and recovering failed rvs etc */", + " /* we should not overwrite the data at this address with a memset */", + "", + " if (f)", + " { t->s_data->t_info = f;", + " } else", + " { t->s_data->t_info = bfs_grab_trail();", + " }", + " return t;", + "}", + "#else", + "BFS_Slot *", + "bfs_prep_slot(BFS_Trail *f, BFS_Slot *t)", + "{", + " if (t->s_data)", + " { memset(t->s_data, 0, sizeof(BFS_State));", + " } else", + " { t->s_data = (BFS_State *) sh_malloc((ulong) sizeof(BFS_State));", + " }", + " if (f)", + " { t->s_data->t_info = f;", + " } else", + " { t->s_data->t_info = bfs_grab_trail();", + " }", + " return t;", + "}", + "#endif", + "", + "SV_Hold *", + "bfs_new_sv(int n)", + "{ SV_Hold *h;", + "", + " if (bfs_svfree[n])", + " { h = bfs_svfree[n];", + " bfs_svfree[n] = h->nxt;", + " h->nxt = (SV_Hold *) 0;", + " } else", + " { h = (SV_Hold *) sh_malloc((ulong) sizeof(SV_Hold));", + "#if 0", + " h->sz = n;", + "#endif", + " h->sv = (State *) sh_malloc((ulong)(sizeof(State) - VECTORSZ + n));", + " }", + " memcpy((char *)h->sv, (char *)&now, n);", + " return h;", + "}", + "#if NRUNS>0", + "static EV_Hold *kept[VECTORSZ]; /* local */", + "", + "static void", + "bfs_keep(EV_Hold *v)", + "{ EV_Hold *h;", + "", + " for (h = kept[v->sz]; h; h = h->nxt) /* check local list */", + " { if (v->nrpr == h->nrpr", + " && v->nrqs == h->nrqs", + "#if !defined(NOCOMP) && !defined(HC)", + " && (v->sv == h->sv || memcmp((char *) v->sv, (char *) h->sv, v->sz) == 0)", + "#endif", + "#ifdef TRIX", + " )", + "#else", + " #if NRUNS>0", + " #if VECTORSZ>32000", + " && (memcmp((char *) v->po, (char *) h->po, v->nrpr * sizeof(int)) == 0)", + " && (memcmp((char *) v->qo, (char *) h->qo, v->nrqs * sizeof(int)) == 0)", + " #else", + " && (memcmp((char *) v->po, (char *) h->po, v->nrpr * sizeof(short)) == 0)", + " && (memcmp((char *) v->qo, (char *) h->qo, v->nrqs * sizeof(short)) == 0)", + " #endif", + " && (memcmp((char *) v->ps, (char *) h->ps, v->nrpr * sizeof(uchar)) == 0)", + " && (memcmp((char *) v->qs, (char *) h->qs, v->nrqs * sizeof(uchar)) == 0))", + " #else", + " )", + " #endif", + "#endif", + " { break;", + " } }", + "", + " if (!h) /* we don't have one like it yet */", + " { v->nxt = kept[v->sz]; /* keep the original owner field */", + " kept[v->sz] = v;", + " /* all ptrs inside are to shared memory, but nxt is local */", + " }", + "}", + "", + "EV_Hold *", + "bfs_new_sv_mask(int n)", + "{ EV_Hold *h;", + "", + " for (h = kept[n]; h; h = h->nxt)", + " { if ((now._nr_pr == h->nrpr)", + " && (now._nr_qs == h->nrqs)", + "#if !defined(NOCOMP) && !defined(HC) && NRUNS>0", + " && ((char *) Mask == h->sv || (memcmp((char *) Mask, h->sv, n) == 0))", + "#endif", + "#ifdef TRIX", + " )", + "#else", + " #if NRUNS>0", + " #if VECTORSZ>32000", + " && (memcmp((char *) proc_offset, (char *) h->po, now._nr_pr * sizeof(int)) == 0)", + " && (memcmp((char *) q_offset, (char *) h->qo, now._nr_qs * sizeof(int)) == 0)", + " #else", + " && (memcmp((char *) proc_offset, (char *) h->po, now._nr_pr * sizeof(short)) == 0)", + " && (memcmp((char *) q_offset, (char *) h->qo, now._nr_qs * sizeof(short)) == 0)", + " #endif", + " && (memcmp((char *) proc_skip, (char *) h->ps, now._nr_pr * sizeof(uchar)) == 0)", + " && (memcmp((char *) q_skip, (char *) h->qs, now._nr_qs * sizeof(uchar)) == 0))", + " #else", + " )", + " #endif", + "#endif", + " { break;", + " } }", + "", + " if (!h)", + " { /* once created, the contents are never modified */", + " h = (EV_Hold *) sh_malloc((ulong)sizeof(EV_Hold));", + " h->owner = who_am_i;", + " h->sz = n;", + " h->nrpr = now._nr_pr;", + " h->nrqs = now._nr_qs;", + "#if !defined(NOCOMP) && !defined(HC) && NRUNS>0", + " h->sv = (char *) Mask; /* in shared memory, and never modified */", + "#endif", + "#if NRUNS>0 && !defined(TRIX)", + " if (now._nr_pr > 0)", + " { h->ps = (char *) proc_skip;", + " h->po = (char *) proc_offset;", + " }", + " if (now._nr_qs > 0)", + " { h->qs = (char *) q_skip;", + " h->qo = (char *) q_offset;", + " }", + "#endif", + " h->nxt = kept[n];", + " kept[n] = h;", + " }", + " return h;", + "}", + "#endif", /* NRUNS>0 */ + "BFS_Slot *", + "bfs_pack_state(Trail *f, BFS_Trail *g, int search_depth, BFS_Slot *t)", + "{", + "#ifdef BFS_CHECK", + " assert(t->s_data != NULL);", + " assert(t->s_data->t_info != NULL);", + " assert(f || g);", + "#endif", + " if (!g)", + " { t->s_data->t_info->ostate = f->ostate;", + " t->s_data->t_info->st = f->st;", + " t->s_data->t_info->o_tt = search_depth;", + " t->s_data->t_info->pr = f->pr;", + " t->s_data->t_info->tau = f->tau;", + " t->s_data->t_info->o_pm = f->o_pm;", + " if (f->o_t)", + " { t->s_data->t_info->t_id = f->o_t->t_id;", + " } else", + " { t->s_data->t_info->t_id = -1;", + " t->s_data->t_info->ostate = NULL;", + " }", + " } /* else t->s_data->t_info == g */", + "#if SYNC", + " t->s_data->boq = boq;", + "#endif", + "#ifdef VERBOSE", + " { static ulong u_cnt;", + " t->s_data->nr = u_cnt++;", + " }", + "#endif", + "#ifdef TRIX", + " sv_populate(); /* make sure now is up to date */", + "#endif", + "#ifndef BFS_DISK", + " { SV_Hold *x = bfs_new_sv(vsize);", + " t->s_data->osv = x->sv;", + " x->sv = (State *) 0;", + " x->nxt = bfs_free_hold;", + " bfs_free_hold = x;", + " }", + "#endif", + "#if NRUNS>0", + " t->s_data->omask = bfs_new_sv_mask(vsize);", + "#endif", + "", + "#if defined(Q_PROVISO) && !defined(BITSTATE) && !defined(NOREDUCE)", + " t->s_data->lstate = Lstate; /* Lstate is set in o_store or h_store */", + "#endif", + "#ifdef BFS_FIFO", + " t->type = STATE;", + "#endif", + " return t;", + "}", + "", + "void", + "bfs_store_state(Trail *t, short oboq)", + "{", + "#ifdef TRIX", + " sv_populate();", + "#endif", + "#if defined(VERI) && defined(Q_PROVISO) && !defined(BITSTATE) && defined(FULLSTACK)", + " if (!(t->tau&4)", /* prog move */ + " && t->ostate)", /* not initial state */ + " { t->tau |= ((BFS_Trail *) t->ostate)->tau&64;", + " } /* lift 64 across claim moves */", + "#endif", + "", + "#ifdef BFS_SEP_HASH", + " #if SYNC", + " if (boq == -1 && oboq != -1) /* post-rv */", + " { BFS_Trail *x = (BFS_Trail *) trpt->ostate; /* pre-rv state */", + " if (x)", + " { x->o_pm |= 4; /* rv complete */", + " } }", + " #endif", + " d_sfh((uchar *)&now, (int) vsize); /* sep-hash -- sets K1 -- overkill */", + " bfs_keep_state = K1%%Cores + 1;", + " bfs_push_state(t, NULL, trpt->o_tt+1); /* bfs_store_state - sep_hash */", + " bfs_keep_state = 0;", + "#else", + " #ifdef VERI", +#if 0 + in VERI mode store the state when + (!t->ostate || (t->tau&4)) in initial state and after each program move + + i.e., dont store when !(!t->ostate || (t->tau&4)) = (t->ostate && !(t->tau&4)) + the *first* time that the tau flag is not set: + possibly after a series of claim moves in an atomic sequence +#endif + " if (!(t->tau&4) && t->ostate && (((BFS_Trail *)t->ostate)->tau&4))", + " { /* do not store intermediate state */", + " #if defined(VERBOSE) && defined(L_BOUND)", + " bfs_printf(\"Un-Stored state bnd %%d -- sds %%p\\n\",", + " now._l_bnd, now._l_sds);", + " #endif", + " bfs_push_state(t, NULL, trpt->o_tt+1); /* claim move */", + " } else", + " #endif", + " if (!bfs_do_store((char *)&now, vsize)) /* includes bfs_visited */", + " { nstates++; /* local count */", + " trpt->tau |= 64; /* bfs: succ outside stack */", + " #if SYNC", + " if (boq == -1 && oboq != -1) /* post-rv */", + " { BFS_Trail *x = ", + " (BFS_Trail *) trpt->ostate; /* pre-rv state */", + " if (x)", + " { x->o_pm |= 4; /* rv complete */", + " } }", + " #endif", + " bfs_push_state(t, NULL, trpt->o_tt+1); /* successor */", + " } else", + " { truncs++;", + " #ifdef BFS_CHECK", + " bfs_printf(\"seen before\\n\");", + " #endif", + " #if defined(Q_PROVISO) && !defined(BITSTATE) && defined(FULLSTACK)", + " #ifdef USE_TDH", + " if (Lstate)", /* if BFS_INQ is set */ + " { trpt->tau |= 64;", + " }", + " #else", + " if (Lstate && Lstate->tagged) /* bfs_store_state */", + " { trpt->tau |= 64;", + " }", + " #endif", + " #endif", + " }", + "#endif", + "}", + "", + "/*** support routines ***/", + "", + "void", + "bfs_clear_locks(void)", + "{ int i;", + "", + " /* clear any locks held by this process only */", + " if (shared_memory)", + " for (i = 0; i < BFS_MAXLOCKS; i++)", + " { if (shared_memory->sh_owner[i] == who_am_i + 1)", + " { shared_memory->sh_locks[i] = 0;", + "#ifdef BFS_CHECK", + " shared_memory->in_count[i] = 0;", + "#endif", + " shared_memory->sh_owner[i] = 0;", + " } }", + "}", + "", + "void", + "e_critical(int which)", + "{ int w;", + "#ifdef BFS_CHECK", + " assert(which >= 0 && which < BFS_MAXLOCKS);", + "#endif", + " if (shared_memory == NULL) return;", + " while (tas(&(shared_memory->sh_locks[which])) != 0)", + " { w = shared_memory->sh_owner[which]; /* sh_locks[which] could be 0 by now */", + " assert(w >= 0 && w <= BFS_MAXPROCS);", + " if (w > 0 && shared_memory->bfs_flag[w-1] == 2)", + " { /* multiple processes can get here; only one should do this: */", + " if (tas(&(shared_memory->bfs_data[w - 1].override)) == 0)", + " { fprintf(stderr, \"cpu%%02d: override lock %%d - held by %%d\\n\",", + " who_am_i, which, shared_memory->sh_owner[which]);", + "#ifdef BFS_CHECK", + " shared_memory->in_count[which] = 0;", + "#endif", + " shared_memory->sh_locks[which] = 0;", + " shared_memory->sh_owner[which] = 0;", + " } }", + " shared_memory->wait_count[which]++; /* not atomic of course */", + " }", + "#ifdef BFS_CHECK", + " if (shared_memory->in_count[which] != 0)", + " { fprintf(stderr, \"cpu%%02d: cannot happen lock %%d count %%d\\n\", who_am_i,", + " which, shared_memory->in_count[which]);", + " }", + " shared_memory->in_count[which]++;", + "#endif", + " shared_memory->sh_owner[which] = who_am_i+1;", + "}", + "", + "void", + "x_critical(int which)", + "{", + " if (shared_memory == NULL) return;", + "#ifdef BFS_CHECK", + " assert(shared_memory->in_count[which] == 1);", + " shared_memory->in_count[which] = 0;", + "#endif", + " shared_memory->sh_locks[which] = 0;", + " shared_memory->sh_owner[which] = 0;", + "}", + "", + "void", + "bfs_printf(const char *fmt, ...)", + "{ va_list args;", + "", + " e_critical(BFS_PRINT);", + "#ifdef BFS_CHECK", + " if (1) { int i=who_am_i; while (i-- > 0) printf(\" \"); }", + "#endif", + " printf(\"cpu%%02d: \", who_am_i);", + " va_start(args, fmt);", + " vprintf(fmt, args);", + " va_end(args);", + " fflush(stdout);", + " x_critical(BFS_PRINT);", + "}", + "", + "int", + "bfs_all_idle(void)", + "{ int i;", + "", + " if (shared_memory)", + " for (i = 0; i < Cores; i++)", + " { if (shared_memory->bfs_flag[i] == 0", + " && shared_memory->bfs_idle[i] == 0)", + " { return 0;", + " } }", + " return 1;", + "}", + "", + "#ifdef BFS_FIFO", + "int", + "bfs_idle_and_empty(void)", + "{ int p; /* read-only */", + " for (p = 0; p < Cores; p++)", + " { if (shared_memory->bfs_flag[p] == 0", + " && shared_memory->bfs_idle[p] == 0)", + " { return 0;", + " } }", + " for (p = 0; p < Cores; p++)", + " { if (bfs_empty(p) < Cores)", + " { return 0;", + " } }", + " return 1;", + "}", + "#endif", + "", + "void", + "bfs_set_toggle(void) /* executed by root */", + "{ int i;", + "", + " if (shared_memory)", + " for (i = 0; i < Cores; i++)", + " { shared_memory->bfs_idle[i] = 0;", + " }", + "}", + "", + "int", + "bfs_all_running(void) /* crash detection */", + "{ int i;", + " for (i = 0; i < Cores; i++)", + " { if (!shared_memory || shared_memory->bfs_flag[i] > 1)", + " { return 0;", + " } }", + " return 1;", + "}", + "", + "void", + "bfs_mark_done(int code)", + "{", + " if (shared_memory)", + " { shared_memory->bfs_flag[who_am_i] = (int) code;", + " shared_memory->quit = 1;", + " }", + "}", + "", + "static uchar *", + "bfs_offset(int c)", + "{ int p, N;", + "#ifdef COLLAPSE", + " uchar *q = (uchar *) ncomps; /* it is the first object allocated */", + " q += (256+2) * sizeof(ulong); /* preserve contents of ncomps */", + "#else", + " uchar *q = (uchar *) &(shared_memory->allocator);", + "#endif", + " /* _NP_+1 proctypes, reachability info:", + " * reached[x : 0 .. _NP_+1][ 0 .. NrStates[x] ]", + " */", + " for (p = N = 0; p <= _NP_; p++)", + " { N += NrStates[p]; /* sum for all proctypes */", + " }", + "", + " /* space needed per proctype: N bytes */", + " /* rounded up to a multiple of the word size */", + " if ((N%%sizeof(void *)) != 0) /* aligned */", + " { N += sizeof(void *) - (N%%sizeof(void *));", + " }", + "", + " q += ((c - 1) * (_NP_ + 1) * N);", + " return q;", + "}", + "", + "static void", + "bfs_putreached(void)", + "{ uchar *q;", + " int p;", + "", + " assert(who_am_i > 0);", + "", + " q = bfs_offset(who_am_i);", + " for (p = 0; p <= _NP_; p++)", + " { memcpy((void *) q, (const void *) reached[p], (size_t) NrStates[p]);", + " q += NrStates[p];", + " }", + "}", + "", + "static void", + "bfs_getreached(int c)", + "{ uchar *q;", + " int p, i;", + "", + " assert(who_am_i == 0 && c >= 1 && c < Cores);", + "", + " q = (uchar *) bfs_offset(c);", + " for (p = 0; p <= _NP_; p++)", + " for (i = 0; i < NrStates[p]; i++)", + " { reached[p][i] += *q++; /* update local copy */", + " }", + "}", + "", + "void", + "bfs_update(void)", + "{ int i;", + " volatile BFS_data *s;", + "", + " if (!shared_memory) return;", + "", + " s = &shared_memory->bfs_data[who_am_i];", + " if (who_am_i == 0)", + " { shared_memory->bfs_flag[who_am_i] = 3; /* or else others dont stop */", + " bfs_gcount = 0;", + " for (i = 1; i < Cores; i++) /* start at 1 not 0 */", + " { while (shared_memory->bfs_flag[i] == 0)", + " { sleep(1);", + " if (bfs_gcount++ > WAIT_MAX) /* excessively long wait */", + " { printf(\"cpu00: give up waiting for cpu%%2d (%%d cores)\\n\", i, Cores);", + " bfs_gcount = 0;", + " break;", + " } }", + " s = &shared_memory->bfs_data[i];", + " mreached = Max(mreached, s->mreached);", + " hmax = vsize = Max(vsize, s->vsize);", + " errors += s->errors;", + " memcnt += s->memcnt;", + " nstates += s->nstates;", + " nlinks += s->nlinks;", + " truncs += s->truncs;", + " bfs_left += s->memory_left;", + " bfs_punt += s->punted;", + " bfs_getreached(i);", + " }", + " } else", + " { s->mreached = (ulong) mreached;", + " s->vsize = (ulong) vsize;", + " s->errors = (int) errors;", + " s->memcnt = (double) memcnt;", + " s->nstates = (double) nstates;", + " s->nlinks = (double) nlinks;", + " s->truncs = (double) truncs;", + " s->memory_left = (ulong) bfs_left;", + " s->punted = (ulong) bfs_punt;", + " bfs_putreached();", + " }", + "}", + "", + "volatile uchar *", + "sh_pre_malloc(ulong n) /* used before the local heaps are populated */", + "{ volatile uchar *ptr = NULL;", + "", + " assert(!bfs_runs);", + " if ((n%%sizeof(void *)) != 0)", + " { n += sizeof(void *) - (n%%sizeof(void *));", + " assert((n%%sizeof(void *)) == 0);", + " }", + "", + " e_critical(BFS_MEM); /* needed? */", + " if (shared_memory->mem_left < n + 7)", /* 7 for possible alignment */ + " { x_critical(BFS_MEM);", + " bfs_printf(\"want %%lu, have %%lu\\n\",", + " n, shared_memory->mem_left);", + " bfs_shutdown(\"out of shared memory\");", + " assert(0); /* should be unreachable */", + " }", + " ptr = shared_memory->allocator;", + "#if WS>4", /* align to 8 byte boundary */ + " { int b = (int) ((uint64_t) ptr)&7;", + " if (b != 0)", + " { ptr += (8-b);", + " shared_memory->allocator = ptr;", + " } }", + "#endif", + " shared_memory->allocator += n;", + " shared_memory->mem_left -= n;", + " x_critical(BFS_MEM);", + "", + " bfs_pre_allocated += n;", + "", + " return ptr;", + "}", + "", + "volatile uchar *", + "sh_malloc(ulong n)", + "{ volatile uchar *ptr = NULL;", + "#ifdef BFS_CHECK", + " assert(bfs_runs);", + "#endif", + " if ((n%%sizeof(void *)) != 0)", + " { n += sizeof(void *) - (n%%sizeof(void *));", + "#ifdef BFS_CHECK", + " assert((n%%sizeof(void *)) == 0);", + "#endif", + " }", + "", + " /* local heap -- no locks needed */", + " if (bfs_left < n)", + " { e_critical(BFS_MEM);", + " if (shared_memory->mem_left >= n)", + " { ptr = (uchar *) shared_memory->allocator;", + " shared_memory->allocator += n;", + " shared_memory->mem_left -= n;", + " x_critical(BFS_MEM);", + " return ptr;", + " }", + " x_critical(BFS_MEM);", + "#ifdef BFS_LOGMEM", + " int i;", + " e_critical(BFS_MEM);", + " for (i = 0; i < 1024; i++)", + " { if (shared_memory->logmem[i] > 0)", + " { bfs_printf(\"\tlog[%%d]\t%%d\\n\", i, shared_memory->logmem[i]);", + " } }", + " x_critical(BFS_MEM);", + "#endif", + " bfs_shutdown(\"out of shared memory\"); /* no return */", + " }", + "#ifdef BFS_LOGMEM", + " e_critical(BFS_MEM);", + " if (n < 1023)", + " { shared_memory->logmem[n]++;", + " } else", + " { shared_memory->logmem[1023]++;", + " }", + " x_critical(BFS_MEM);", + "#endif", + " ptr = (uchar *) bfs_heap;", + " bfs_heap += n;", + " bfs_left -= n;", + "", + " if (0) printf(\"sh_malloc %%ld\\n\", n);", + " return ptr;", + "}", + "", + "volatile uchar *", + "bfs_get_shared_mem(key_t key, size_t n)", + "{ char *rval;", + "", + " assert(who_am_i == 0);", + "", + " shared_mem_id = shmget(key, n, 0600 | IPC_CREAT | IPC_EXCL); /* create */", + " if (shared_mem_id == -1)", + " { fprintf(stderr, \"cpu%%02d: tried to get %%d MB of shared memory\\n\",", + " who_am_i, (int) n/(1024*1024));", + " perror(\"shmget\");", + " exit(1);", + " }", + " if ((rval = (char *) shmat(shared_mem_id, (void *) 0, 0)) == (char *) -1) /* attach */", + " { perror(\"shmat\");", + " exit(1);", + " }", + " return (uchar *) rval;", + "}", + "", + "void", + "bfs_drop_shared_memory(void)", + "{", + " if (who_am_i == 0)", + " { printf(\"pan: releasing shared memory...\");", + " fflush(stdout);", + " }", + " if (shared_memory)", + " { shmdt(shared_memory); /* detach */", + " if (who_am_i == 0)", + " { shmctl(shared_mem_id, IPC_RMID, (void *) 0); /* remove */", + " } }", + " if (who_am_i == 0)", + " { printf(\"done\\n\");", + " fflush(stdout);", + " }", + "}", + "", + "size_t", + "bfs_find_largest(key_t key)", + "{ size_t n;", + " const size_t delta = 32*1024*1024;", + " int temp_id = -1;", + " int atleastonce = 0;", + "", + " for (n = delta; ; n += delta)", + " { if (WS <= 4 && n >= 1024*1024*1024)", /* was n >= INT_MAX */ + " { n = 1024*1024*1024;", + " break;", + " }", + "#ifdef MEMLIM", + " if ((double) n > memlim)", + " { n = (size_t) memlim;", + " break;", + " }", + "#endif", + " temp_id = shmget(key, n, 0600); /* check for stale copy */", + " if (temp_id != -1)", + " { if (shmctl(temp_id, IPC_RMID, ((void *) 0)) < 0) /* remove */", + " { perror(\"remove_segment_fails 2\");", + " exit(1);", + " } }", + "", + " temp_id = shmget(key, n, 0600 | IPC_CREAT | IPC_EXCL); /* create new */", + " if (temp_id == -1)", + " { n -= delta;", + " break;", + " } else", + " { atleastonce++;", + " if (shmctl(temp_id, IPC_RMID, ((void *) 0)) < 0)", + " { perror(\"remove_segment_fails 0\");", + " exit(1);", + " } } }", + "", + " if (!atleastonce)", + " { printf(\"cpu%%02d: no shared memory n=%%d\\n\", who_am_i, (int) n);", + " exit(1);", + " }", + "", + " printf(\"cpu%%02d: largest shared memory segment: %%lu MB\\n\",", + " who_am_i, (ulong) n/(1024*1024));", + "#if 0", + " #ifdef BFS_SEP_HASH", + " n /= 2; /* not n /= Cores because the queues take most memory */", + " printf(\"cpu%%02d: using %%lu MB\\n\", who_am_i, (ulong) n/(1024*1024));", + " #endif", + "#endif", + " fflush(stdout);", + "", + " if ((n/(1024*1024)) == 32)", + " { if (sizeof(void *) == 4) /* a 32 bit machine */", + " { fprintf(stderr, \"\\t32MB is the default; increase it to 1 GB with:\\n\");", + " fprintf(stderr, \"\\tsudo /sbin/sysctl kernel.shmmax=%%d\\n\", (1<<30));", + " fprintf(stderr, \"\\tsudo /sbin/sysctl kernel.shmall=%%d\\n\", (1<<30)/8192);", + " } else if (sizeof(void *) == 8) /* a 64 bit machine */", + " { fprintf(stderr, \"\\t32MB is the default; increase it to 30 GB with:\\n\");", + " fprintf(stderr, \"\\tsudo /sbin/sysctl kernel.shmmax=32212254720\\n\");", + " fprintf(stderr, \"\\tsudo /sbin/sysctl kernel.shmall=7864320\\n\");", + " fprintf(stderr, \"\\tor for 60 GB:\\n\");", + " fprintf(stderr, \"\\tsudo /sbin/sysctl kernel.shmmax=60000000000\\n\");", + " fprintf(stderr, \"\\tsudo /sbin/sysctl kernel.shmall=30000000\\n\");", + " } else", + " { fprintf(stderr, \"\\tweird wordsize %%d\\n\", (int) sizeof(void *));", + " } }", + "", + " return n;", + "}", + "#ifdef BFS_DISK", + "void", + "bfs_disk_start(void)", /* setup .spin*/ + "{ int unused = system(\"rm -fr .spin\");", + " if (mkdir(\".spin\", 0777) != 0)", + " { perror(\"mkdir\");", + " Uerror(\"aborting\");", + " }", + "}", + "void", + "bfs_disk_stop(void)", /* remove .spin */ + "{", + " if (system(\"rm -fr .spin\") < 0)", + " { perror(\"rm -fr .spin/\");", + " }", + "}", + "void", + "bfs_disk_inp(void)", /* this core only */ + "{ int i; char fnm[16];", + "#ifdef VERBOSE", + " bfs_printf(\"inp %%d %%d 0..%%d\\n\", bfs_toggle, who_am_i, Cores);", + "#endif", + " for (i = 0; i < Cores; i++)", + " { sprintf(fnm, \".spin/q%%d_%%d_%%d\", bfs_toggle, who_am_i, i);", + " if ((bfs_inp_fd[i] = open(fnm, 0444)) < 0)", + " { perror(\"open\");", + " Uerror(fnm);", + " } }", + "}", + "void", + "bfs_disk_out(void)", /* this core only */ + "{ int i; char fnm[16];", + "#ifdef VERBOSE", + " bfs_printf(\"out %%d 0..%%d %%d\\n\", 1-bfs_toggle, Cores, who_am_i);", + "#endif", + " shared_memory->bfs_out_cnt[who_am_i] = 0;", + " for (i = 0; i < Cores; i++)", + " { sprintf(fnm, \".spin/q%%d_%%d_%%d\", 1-bfs_toggle, i, who_am_i);", + " if ((bfs_out_fd[i] = creat(fnm, 0666)) < 0)", + " { perror(\"creat\");", + " Uerror(fnm);", + " } }", + "}", + "void", + "bfs_disk_iclose(void)", + "{ int i;", + "#ifdef VERBOSE", + " bfs_printf(\"close_inp\\n\");", + "#endif", + " for (i = 0; i < Cores; i++)", + " { if (close(bfs_inp_fd[i]) < 0)", + " { perror(\"iclose\");", + " } }", + "}", + "void", + "bfs_disk_oclose(void)", + "{ int i;", + "#ifdef VERBOSE", + " bfs_printf(\"close_out\\n\");", + "#endif", + " for (i = 0; i < Cores; i++)", + " { if (fsync(bfs_out_fd[i]) < 0)", + " { perror(\"fsync\");", + " }", + " if (close(bfs_out_fd[i]) < 0)", + " { perror(\"oclose\");", + " } }", + "}", + "#endif", + "void", + "bfs_write_snap(int fd)", + "{ if (write(fd, snap, strlen(snap)) != strlen(snap))", + " { printf(\"pan: error writing %%s\\n\", fnm);", + " bfs_shutdown(\"file system error\");", + " }", + "}", + "", + "void", + "bfs_one_step(BFS_Trail *t, int fd)", + "{ if (t && t->t_id != (T_ID) -1)", + " { sprintf(snap, \"%%d:%%d:%%d\\n\",", + " trcnt++, t->pr, t->t_id);", + " bfs_write_snap(fd);", + " }", + "}", + "", + "void", + "bfs_putter(BFS_Trail *t, int fd)", + "{ if (t && t != (BFS_Trail *) t->ostate)", + " bfs_putter((BFS_Trail *) t->ostate, fd);", + "#ifdef L_BOUND", + " if (depthfound == trcnt)", + " { strcpy(snap, \"-1:-1:-1\\n\");", + " bfs_write_snap(fd);", + " depthfound = -1;", + " }", + "#endif", + " bfs_one_step(t, fd);", + "}", + "", + "void", + "bfs_nuerror(char *str)", + "{ int fd = make_trail();", + "", + " if (fd < 0) return;", + "#ifdef VERI", + " sprintf(snap, \"-2:%%d:-2\\n\", (uchar) ((P0 *)pptr(0))->_t);", + " bfs_write_snap(fd);", + "#endif", + "#ifdef MERGED", + " sprintf(snap, \"-4:-4:-4\\n\");", + " bfs_write_snap(fd);", + "#endif", + " trcnt = 1;", + " if (strstr(str, \"invalid\"))", + " { bfs_putter((BFS_Trail *) trpt->ostate, fd);", + " } else", + " { BFS_Trail x;", + " memset((char *) &x, 0, sizeof(BFS_Trail));", + " x.pr = trpt->pr;", + " x.t_id = (trpt->o_t)?trpt->o_t->t_id:0;", + " x.ostate = trpt->ostate;", + " bfs_putter(&x, fd);", + " }", + " close(fd);", + " if (errors >= upto && upto != 0)", + " { bfs_shutdown(str);", + " }", + "}", + "", + "void", + "bfs_uerror(char *str)", + "{ static char laststr[256];", + "", + " errors++;", + " if (strncmp(str, laststr, 254) != 0)", + " { bfs_printf(\"pan:%%d: %%s (at depth %%ld)\\n\",", + " errors, str, ((depthfound == -1)?depth:depthfound));", + " strncpy(laststr, str, 254);", + " }", + "#ifdef HAS_CODE", + " if (readtrail) { wrap_trail(); return; }", + "#endif", + " if (every_error != 0 || errors == upto)", + " { bfs_nuerror(str);", + " }", + " if (errors >= upto && upto != 0)", + " { bfs_shutdown(\"bfs_uerror\");", + " }", + " depthfound = -1;", + "}\n", + "void", + "bfs_Uerror(char *str)", + "{ /* bfs_uerror(str); */", + " bfs_printf(\"pan:%%d: %%s (at depth %%ld)\\n\", ++errors, str,", + " ((depthfound == -1)?depth:depthfound));", + " bfs_shutdown(\"bfs_Uerror\");", + "}", + 0, +}; diff --git a/sys/src/cmd/spin/reprosrc.c b/sys/src/cmd/spin/reprosrc.c index 0d4ba6be7..d418eaf59 100644 --- a/sys/src/cmd/spin/reprosrc.c +++ b/sys/src/cmd/spin/reprosrc.c @@ -1,22 +1,21 @@ /***** 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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #include +#include #include "spin.h" #include "y.tab.h" static int indent = 1; +extern YYSTYPE yylval; extern ProcList *rdy; -void repro_seq(Sequence *); +static void repro_seq(Sequence *); void doindent(void) @@ -48,7 +47,7 @@ repro_sub(Element *e) printf(" };\n"); } -void +static void repro_seq(Sequence *s) { Element *e; Symbol *v; @@ -96,7 +95,7 @@ repro_seq(Sequence *s) doindent(); if (e->n->ntyp == C_CODE) { printf("c_code "); - plunk_inline(stdout, e->n->sym->name, 1); + plunk_inline(stdout, e->n->sym->name, 1, 1); } else if (e->n->ntyp == 'c' && e->n->lft->ntyp == C_EXPR) { printf("c_expr { "); @@ -134,3 +133,252 @@ repro_src(void) { repro_proc(rdy); } + +static int in_decl; +static int in_c_decl; +static int in_c_code; + +void +blip(int n, char *b) +{ char mtxt[1024]; + + strcpy(mtxt, ""); + + switch (n) { + default: if (n > 0 && n < 256) + sprintf(mtxt, "%c", n); + else + sprintf(mtxt, "<%d?>", n); + + break; + case '(': strcpy(mtxt, "("); in_decl++; break; + case ')': strcpy(mtxt, ")"); in_decl--; break; + case '{': strcpy(mtxt, "{"); break; + case '}': strcpy(mtxt, "}"); break; + case '\t': sprintf(mtxt, "\\t"); break; + case '\f': sprintf(mtxt, "\\f"); break; + case '\n': sprintf(mtxt, "\\n"); break; + case '\r': sprintf(mtxt, "\\r"); break; + case 'c': sprintf(mtxt, "condition"); break; + case 's': sprintf(mtxt, "send"); break; + case 'r': sprintf(mtxt, "recv"); break; + case 'R': sprintf(mtxt, "recv poll"); break; + case '@': sprintf(mtxt, "@"); break; + case '?': sprintf(mtxt, "(x->y:z)"); break; + case NEXT: sprintf(mtxt, "X"); break; + case ALWAYS: sprintf(mtxt, "[]"); break; + case EVENTUALLY: sprintf(mtxt, "<>"); break; + case IMPLIES: sprintf(mtxt, "->"); break; + case EQUIV: sprintf(mtxt, "<->"); break; + case UNTIL: sprintf(mtxt, "U"); break; + case WEAK_UNTIL: sprintf(mtxt, "W"); break; + case IN: sprintf(mtxt, "in"); break; + case ACTIVE: sprintf(mtxt, "active"); break; + case AND: sprintf(mtxt, "&&"); break; + case ARROW: sprintf(mtxt, "->"); break; + case ASGN: sprintf(mtxt, "="); break; + case ASSERT: sprintf(mtxt, "assert"); break; + case ATOMIC: sprintf(mtxt, "atomic"); break; + case BREAK: sprintf(mtxt, "break"); break; + case C_CODE: sprintf(mtxt, "c_code"); in_c_code++; break; + case C_DECL: sprintf(mtxt, "c_decl"); in_c_decl++; break; + case C_EXPR: sprintf(mtxt, "c_expr"); break; + case C_STATE: sprintf(mtxt, "c_state"); break; + case C_TRACK: sprintf(mtxt, "c_track"); break; + case CLAIM: sprintf(mtxt, "never"); break; + case CONST: sprintf(mtxt, "%d", yylval->val); break; + case DECR: sprintf(mtxt, "--"); break; + case D_STEP: sprintf(mtxt, "d_step"); break; + case D_PROCTYPE: sprintf(mtxt, "d_proctype"); break; + case DO: sprintf(mtxt, "do"); break; + case DOT: sprintf(mtxt, "."); break; + case ELSE: sprintf(mtxt, "else"); break; + case EMPTY: sprintf(mtxt, "empty"); break; + case ENABLED: sprintf(mtxt, "enabled"); break; + case EQ: sprintf(mtxt, "=="); break; + case EVAL: sprintf(mtxt, "eval"); break; + case FI: sprintf(mtxt, "fi"); break; + case FULL: sprintf(mtxt, "full"); break; + case GE: sprintf(mtxt, ">="); break; + case GET_P: sprintf(mtxt, "get_priority"); break; + case GOTO: sprintf(mtxt, "goto"); break; + case GT: sprintf(mtxt, ">"); break; + case HIDDEN: sprintf(mtxt, "hidden"); break; + case IF: sprintf(mtxt, "if"); break; + case INCR: sprintf(mtxt, "++"); break; + + case INLINE: sprintf(mtxt, "inline"); break; + case INIT: sprintf(mtxt, "init"); break; + case ISLOCAL: sprintf(mtxt, "local"); break; + + case LABEL: sprintf(mtxt, ""); break; + + case LE: sprintf(mtxt, "<="); break; + case LEN: sprintf(mtxt, "len"); break; + case LSHIFT: sprintf(mtxt, "<<"); break; + case LT: sprintf(mtxt, "<"); break; + case LTL: sprintf(mtxt, "ltl"); break; + + case NAME: sprintf(mtxt, "%s", yylval->sym->name); break; + + case XU: switch (yylval->val) { + case XR: sprintf(mtxt, "xr"); break; + case XS: sprintf(mtxt, "xs"); break; + default: sprintf(mtxt, ""); break; + } + break; + + case TYPE: switch (yylval->val) { + case BIT: sprintf(mtxt, "bit"); break; + case BYTE: sprintf(mtxt, "byte"); break; + case CHAN: sprintf(mtxt, "chan"); in_decl++; break; + case INT: sprintf(mtxt, "int"); break; + case MTYPE: sprintf(mtxt, "mtype"); break; + case SHORT: sprintf(mtxt, "short"); break; + case UNSIGNED: sprintf(mtxt, "unsigned"); break; + default: sprintf(mtxt, ""); break; + } + break; + + case NE: sprintf(mtxt, "!="); break; + case NEG: sprintf(mtxt, "!"); break; + case NEMPTY: sprintf(mtxt, "nempty"); break; + case NFULL: sprintf(mtxt, "nfull"); break; + + case NON_ATOMIC: sprintf(mtxt, ""); break; + + case NONPROGRESS: sprintf(mtxt, "np_"); break; + case OD: sprintf(mtxt, "od"); break; + case OF: sprintf(mtxt, "of"); break; + case OR: sprintf(mtxt, "||"); break; + case O_SND: sprintf(mtxt, "!!"); break; + case PC_VAL: sprintf(mtxt, "pc_value"); break; + case PRINT: sprintf(mtxt, "printf"); break; + case PRINTM: sprintf(mtxt, "printm"); break; + case PRIORITY: sprintf(mtxt, "priority"); break; + case PROCTYPE: sprintf(mtxt, "proctype"); break; + case PROVIDED: sprintf(mtxt, "provided"); break; + case RCV: sprintf(mtxt, "?"); break; + case R_RCV: sprintf(mtxt, "??"); break; + case RSHIFT: sprintf(mtxt, ">>"); break; + case RUN: sprintf(mtxt, "run"); break; + case SEP: sprintf(mtxt, "::"); break; + case SEMI: sprintf(mtxt, ";"); break; + case SET_P: sprintf(mtxt, "set_priority"); break; + case SHOW: sprintf(mtxt, "show"); break; + case SND: sprintf(mtxt, "!"); break; + + case INAME: + case UNAME: + case PNAME: + case STRING: sprintf(mtxt, "%s", yylval->sym->name); break; + + case TRACE: sprintf(mtxt, "trace"); break; + case TIMEOUT: sprintf(mtxt, "timeout"); break; + case TYPEDEF: sprintf(mtxt, "typedef"); break; + case UMIN: sprintf(mtxt, "-"); break; + case UNLESS: sprintf(mtxt, "unless"); break; + } + strcat(b, mtxt); +} + +void +purge(char *b) +{ + if (strlen(b) == 0) return; + + if (b[strlen(b)-1] != ':') /* label? */ + { if (b[0] == ':' && b[1] == ':') + { indent--; + doindent(); + indent++; + } else + { doindent(); + } + } + printf("%s\n", b); + strcpy(b, ""); + + in_decl = 0; + in_c_code = 0; + in_c_decl = 0; +} + +int pp_mode; +extern int lex(void); + +void +pretty_print(void) +{ int c, lastc = 0; + char buf[1024]; + + pp_mode = 1; + indent = 0; + strcpy(buf, ""); + while ((c = lex()) != EOF) + { + if ((lastc == IF || lastc == DO) && c != SEP) + { indent--; /* c_code if */ + } + if (c == C_DECL || c == C_STATE + || c == C_TRACK || c == SEP + || c == DO || c == IF + || (c == TYPE && !in_decl)) + { purge(buf); /* start on new line */ + } + + if (c == '{' + && lastc != OF && lastc != IN + && lastc != ATOMIC && lastc != D_STEP + && lastc != C_CODE && lastc != C_DECL && lastc != C_EXPR) + { purge(buf); + } + + if (c == PREPROC) + { int oi = indent; + purge(buf); + assert(strlen(yylval->sym->name) < sizeof(buf)); + strcpy(buf, yylval->sym->name); + indent = 0; + purge(buf); + indent = oi; + continue; + } + + if (c != ':' && c != SEMI + && c != ',' && c != '(' + && c != '#' && lastc != '#' + && c != ARROW && lastc != ARROW + && c != '.' && lastc != '.' + && c != '!' && lastc != '!' + && c != SND && lastc != SND + && c != RCV && lastc != RCV + && c != O_SND && lastc != O_SND + && c != R_RCV && lastc != R_RCV + && (c != ']' || lastc != '[') + && (c != '>' || lastc != '<') + && (c != GT || lastc != LT) + && c != '@' && lastc != '@' + && c != DO && c != OD && c != IF && c != FI + && c != SEP && strlen(buf) > 0) + strcat(buf, " "); + + if (c == '}' || c == OD || c == FI) + { purge(buf); + indent--; + } + blip(c, buf); + + if (c == '{' || c == DO || c == IF) + { purge(buf); + indent++; + } + + if (c == '}' || c == BREAK || c == SEMI + || (c == ':' && lastc == NAME)) + { purge(buf); + } + lastc = c; + } + purge(buf); +} diff --git a/sys/src/cmd/spin/run.c b/sys/src/cmd/spin/run.c index c336feef2..0df4b5f0a 100644 --- a/sys/src/cmd/spin/run.c +++ b/sys/src/cmd/spin/run.c @@ -1,13 +1,10 @@ /***** spin: run.c *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #include #include "spin.h" @@ -16,15 +13,18 @@ extern RunList *X, *run; extern Symbol *Fname; extern Element *LastStep; -extern int Rvous, lineno, Tval, interactive, MadeChoice; +extern int Rvous, lineno, Tval, interactive, MadeChoice, Priority_Sum; extern int TstOnly, verbose, s_trail, xspin, jumpsteps, depth; -extern int nproc, nstop, no_print, like_java; +extern int analyze, nproc, nstop, no_print, like_java, old_priority_rules; +extern short Have_claim; static long Seed = 1; static int E_Check = 0, Escape_Check = 0; static int eval_sync(Element *); static int pc_enabled(Lextok *n); +static int get_priority(Lextok *n); +static void set_priority(Lextok *n, Lextok *m); extern void sr_buf(int, int); void @@ -42,24 +42,23 @@ Rand(void) Element * rev_escape(SeqList *e) -{ Element *r; +{ Element *r = (Element *) 0; - if (!e) - return (Element *) 0; + if (e) + { if ((r = rev_escape(e->nxt)) == ZE) /* reversed order */ + { r = eval_sub(e->this->frst); + } } - if ((r = rev_escape(e->nxt)) != ZE) /* reversed order */ - return r; - - return eval_sub(e->this->frst); + return r; } Element * eval_sub(Element *e) { Element *f, *g; SeqList *z; - int i, j, k; + int i, j, k, only_pos; - if (!e->n) + if (!e || !e->n) return ZE; #ifdef DEBUG printf("\n\teval_sub(%d %s: line %d) ", @@ -69,8 +68,13 @@ eval_sub(Element *e) #endif if (e->n->ntyp == GOTO) { if (Rvous) return ZE; - LastStep = e; f = get_lab(e->n, 1); + LastStep = e; + f = get_lab(e->n, 1); + f = huntele(f, e->status, -1); /* 5.2.3: was missing */ cross_dsteps(e->n, f->n); +#ifdef DEBUG + printf("GOTO leads to %d\n", f->seqno); +#endif return f; } if (e->n->ntyp == UNLESS) @@ -80,6 +84,7 @@ eval_sub(Element *e) { Element *has_else = ZE; Element *bas_else = ZE; int nr_else = 0, nr_choices = 0; + only_pos = -1; if (interactive && !MadeChoice && !E_Check @@ -89,8 +94,10 @@ eval_sub(Element *e) { printf("Select stmnt ("); whoruns(0); printf(")\n"); if (nproc-nstop > 1) - printf("\tchoice 0: other process\n"); - } + { printf("\tchoice 0: other process\n"); + nr_choices++; + only_pos = 0; + } } for (z = e->sub, j=0; z; z = z->nxt) { j++; if (interactive @@ -113,13 +120,21 @@ eval_sub(Element *e) if (!Enabled0(z->this->frst)) printf("unexecutable, "); else - nr_choices++; + { nr_choices++; + only_pos = j; + } comment(stdout, z->this->frst->n, 0); printf("\n"); } } if (nr_choices == 0 && has_else) - printf("\tchoice %d: (else)\n", nr_else); + { printf("\tchoice %d: (else)\n", nr_else); + only_pos = nr_else; + } + + if (nr_choices <= 1 && only_pos != -1 && !MadeChoice) + { MadeChoice = only_pos; + } if (interactive && depth >= jumpsteps && !Escape_Check @@ -132,8 +147,11 @@ eval_sub(Element *e) else printf("Select [0-%d]: ", j); fflush(stdout); - scanf("%s", buf); - if (isdigit(buf[0])) + if (scanf("%64s", buf) <= 0) + { printf("no input\n"); + return ZE; + } + if (isdigit((int)buf[0])) k = atoi(buf); else { if (buf[0] == 'q') @@ -155,6 +173,7 @@ eval_sub(Element *e) else k = Rand()%j; /* nondeterminism */ } + has_else = ZE; bas_else = ZE; for (i = 0, z = e->sub; i < j+k; i++) @@ -215,7 +234,7 @@ eval_sub(Element *e) } else { SeqList *x; if (!(e->status & (D_ATOM)) - && e->esc && verbose&32) + && e->esc && (verbose&32)) { printf("Stmnt ["); comment(stdout, e->n, 0); printf("] has escape(s): "); @@ -233,12 +252,19 @@ eval_sub(Element *e) #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 +#if 1 + if (!s_trail) /* trail determines selections, new 5.2.5 */ #endif { Escape_Check++; if (like_java) { if ((g = rev_escape(e->esc)) != ZE) { if (verbose&4) - printf("\tEscape taken\n"); + { printf("\tEscape taken (-J) "); + if (g->n && g->n->fn) + printf("%s:%d", g->n->fn->name, g->n->ln); + printf("\n"); + } Escape_Check--; return g; } @@ -246,18 +272,24 @@ eval_sub(Element *e) { for (x = e->esc; x; x = x->nxt) { if ((g = eval_sub(x->this->frst)) != ZE) { if (verbose&4) - printf("\tEscape taken\n"); + { printf("\tEscape taken "); + if (g->n && g->n->fn) + printf("%s:%d", g->n->fn->name, g->n->ln); + printf("\n"); + } Escape_Check--; return g; } } } Escape_Check--; } - switch (e->n->ntyp) { + case ASGN: + if (check_track(e->n) == STRUCT) { break; } + /* else fall thru */ case TIMEOUT: case RUN: case PRINT: case PRINTM: case C_CODE: case C_EXPR: - case ASGN: case ASSERT: + case ASSERT: case 's': case 'r': case 'c': /* toplevel statements only */ LastStep = e; @@ -308,7 +340,8 @@ assign(Lextok *now) t = Sym_typ(now->rgt); break; } - typ_ck(Sym_typ(now->lft), t, "assignment"); + typ_ck(Sym_typ(now->lft), t, "assignment"); + return setval(now->lft, eval(now->rgt)); } @@ -371,6 +404,10 @@ eval(Lextok *now) case NEMPTY: return (qlen(now)>0); case ENABLED: if (s_trail) return 1; return pc_enabled(now->lft); + + case GET_P: return get_priority(now->lft); + case SET_P: set_priority(now->lft->lft, now->lft->rgt); return 1; + case EVAL: return eval(now->lft); case PC_VAL: return pc_value(now->lft); case NONPROGRESS: return nonprogress(); @@ -384,15 +421,21 @@ eval(Lextok *now) 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 ASGN: + if (check_track(now) == STRUCT) { return 1; } + return assign(now); - case C_CODE: printf("%s:\t", now->sym->name); - plunk_inline(stdout, now->sym->name, 0); + case C_CODE: if (!analyze) + { printf("%s:\t", now->sym->name); + plunk_inline(stdout, now->sym->name, 0, 1); + } return 1; /* uninterpreted */ - case C_EXPR: printf("%s:\t", now->sym->name); - plunk_expr(stdout, now->sym->name); - printf("\n"); + case C_EXPR: if (!analyze) + { 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; @@ -407,6 +450,11 @@ eval(Lextok *now) case '.': return 1; /* return label for compound */ case '@': return 0; /* stop state */ case ELSE: return 1; /* only hit here in guided trails */ + + case ',': /* reached through option -A with array initializer */ + case 0: + return 0; /* not great, but safe */ + default : printf("spin: bad node type %d (run)\n", now->ntyp); if (s_trail) printf("spin: trail file doesn't match spec?\n"); fatal("aborting", 0); @@ -426,7 +474,6 @@ printm(FILE *fd, Lextok *n) j = n->lft->val; else j = eval(n->lft); - Buf[0] = '\0'; sr_buf(j, 1); dotag(fd, Buf); } @@ -437,9 +484,9 @@ int interprint(FILE *fd, Lextok *n) { Lextok *tmp = n->lft; char c, *s = n->sym->name; - int i, j; char lbuf[512]; - extern char Buf[]; - char tBuf[4096]; + int i, j; char lbuf[512]; /* matches value in sr_buf() */ + extern char Buf[]; /* global, size 4096 */ + char tBuf[4096]; /* match size of global Buf[] */ Buf[0] = '\0'; if (!no_print) @@ -490,7 +537,7 @@ append: strcat(Buf, lbuf); } dotag(fd, Buf); } - if (strlen(Buf) > 4096) fatal("printf string too long", 0); + if (strlen(Buf) >= 4096) fatal("printf string too long", 0); return 1; } @@ -512,6 +559,7 @@ Enabled1(Lextok *n) verbose = v; return i; + case SET_P: case C_CODE: case C_EXPR: case PRINT: case PRINTM: case ASGN: case ASSERT: @@ -552,6 +600,7 @@ Enabled0(Element *e) case '@': return X->pid == (nproc-nstop-1); case '.': + case SET_P: return 1; case GOTO: if (Rvous) return 0; @@ -594,9 +643,91 @@ pc_enabled(Lextok *n) for (Y = run; Y; Y = Y->nxt) if (--i == pid) { oX = X; X = Y; - result = Enabled0(Y->pc); + result = Enabled0(X->pc); X = oX; break; } return result; } + +int +pc_highest(Lextok *n) +{ int i = nproc - nstop; + int pid = eval(n); + int target = 0, result = 1; + RunList *Y, *oX; + + if (X->prov && !eval(X->prov)) return 0; /* can't be highest unless fully enabled */ + + for (Y = run; Y; Y = Y->nxt) + { if (--i == pid) + { target = Y->priority; + break; + } } +if (0) printf("highest for pid %d @ priority = %d\n", pid, target); + + oX = X; + i = nproc - nstop; + for (Y = run; Y; Y = Y->nxt) + { i--; +if (0) printf(" pid %d @ priority %d\t", Y->pid, Y->priority); + if (Y->priority > target) + { X = Y; +if (0) printf("enabled: %s\n", Enabled0(X->pc)?"yes":"nope"); +if (0) printf("provided: %s\n", eval(X->prov)?"yes":"nope"); + if (Enabled0(X->pc) && (!X->prov || eval(X->prov))) + { result = 0; + break; + } } +else +if (0) printf("\n"); + } + X = oX; + + return result; +} + +int +get_priority(Lextok *n) +{ int i = nproc - nstop; + int pid = eval(n); + RunList *Y; + + if (old_priority_rules) + { return 1; + } + + for (Y = run; Y; Y = Y->nxt) + { if (--i == pid) + { return Y->priority; + } } + return 0; +} + +void +set_priority(Lextok *n, Lextok *p) +{ int i = nproc - nstop - Have_claim; + int pid = eval(n); + RunList *Y; + + if (old_priority_rules) + { return; + } + for (Y = run; Y; Y = Y->nxt) + { if (--i == pid) + { Priority_Sum -= Y->priority; + Y->priority = eval(p); + Priority_Sum += Y->priority; + if (1) + { printf("%3d: setting priority of proc %d (%s) to %d\n", + depth, pid, Y->n->name, Y->priority); + } } } + if (verbose&32) + { printf("\tPid\tName\tPriority\n"); + for (Y = run; Y; Y = Y->nxt) + { printf("\t%d\t%s\t%d\n", + Y->pid, + Y->n->name, + Y->priority); + } } +} diff --git a/sys/src/cmd/spin/sched.c b/sys/src/cmd/spin/sched.c index ee5b87403..d32e3f175 100644 --- a/sys/src/cmd/spin/sched.c +++ b/sys/src/cmd/spin/sched.c @@ -1,13 +1,10 @@ /***** spin: sched.c *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #include #include "spin.h" @@ -19,19 +16,21 @@ extern Ordered *all_names; extern Symbol *Fname, *context; extern int lineno, nr_errs, dumptab, xspin, jumpsteps, columns; extern int u_sync, Elcnt, interactive, TstOnly, cutoff; -extern short has_enabled; -extern int limited_vis; +extern short has_enabled, has_priority, has_code, replay; +extern int limited_vis, product, nclaims, old_priority_rules; +extern int old_scope_rules, scope_seq[128], scope_level, has_stdin; + +extern int pc_highest(Lextok *n); RunList *X = (RunList *) 0; RunList *run = (RunList *) 0; RunList *LastX = (RunList *) 0; /* previous executing proc */ ProcList *rdy = (ProcList *) 0; Element *LastStep = ZE; -int nproc=0, nstop=0, Tval=0; +int nproc=0, nstop=0, Tval=0, Priority_Sum = 0; int Rvous=0, depth=0, nrRdy=0, MadeChoice; short Have_claim=0, Skip_claim=0; -static int Priority_Sum = 0; static void setlocals(RunList *); static void setparams(RunList *, ProcList *, Lextok *); static void talk(RunList *); @@ -42,13 +41,20 @@ runnable(ProcList *p, int weight, int noparams) r->n = p->n; r->tn = p->tn; + r->b = p->b; r->pid = nproc++ - nstop + Skip_claim; + r->priority = weight; + p->priority = (unsigned char) weight; /* not quite the best place of course */ - if ((verbose&4) || (verbose&32)) - printf("Starting %s with pid %d\n", p->n->name, r->pid); - + if (!noparams && ((verbose&4) || (verbose&32))) + { printf("Starting %s with pid %d", + p->n?p->n->name:"--", r->pid); + if (has_priority) printf(" priority %d", r->priority); + printf("\n"); + } if (!p->s) - fatal("parsing error, no sequence %s", p->n?p->n->name:"--"); + 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; @@ -58,14 +64,18 @@ runnable(ProcList *p, int weight, int noparams) r->nxt = run; r->prov = p->prov; - r->priority = weight; + if (weight < 1 || weight > 255) + { fatal("bad process priority, valid range: 1..255", (char *) 0); + } + if (noparams) setlocals(r); Priority_Sum += weight; + run = r; } ProcList * -ready(Symbol *n, Lextok *p, Sequence *s, int det, Lextok *prov) +ready(Symbol *n, Lextok *p, Sequence *s, int det, Lextok *prov, enum btypes b) /* n=name, p=formals, s=body det=deterministic prov=provided */ { ProcList *r = (ProcList *) emalloc(sizeof(ProcList)); Lextok *fp, *fpt; int j; extern int Npars; @@ -73,9 +83,15 @@ ready(Symbol *n, Lextok *p, Sequence *s, int det, Lextok *prov) r->n = n; r->p = p; r->s = s; + r->b = b; r->prov = prov; - r->tn = nrRdy++; - r->det = (short) det; + r->tn = (short) nrRdy++; + n->sc = scope_seq[scope_level]; /* scope_level should be 0 */ + + if (det != 0 && det != 1) + { fprintf(stderr, "spin: bad value for det (cannot happen)\n"); + } + r->det = (unsigned char) det; r->nxt = rdy; rdy = r; @@ -128,13 +144,15 @@ announce(char *w) 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); + { printf("proc %d = %s\n", + run->pid - Have_claim, run->n->name); + } return; } if (dumptab || analyze + || product || s_trail || !(verbose&4)) return; @@ -161,9 +179,11 @@ enable(Lextok *m) Symbol *s = m->sym; /* proctype name */ Lextok *n = m->lft; /* actual parameters */ - if (m->val < 1) m->val = 1; /* minimum priority */ + if (m->val < 1) + { m->val = 1; /* minimum priority */ + } for (p = rdy; p; p = p->nxt) - if (strcmp(s->name, p->n->name) == 0) + { if (strcmp(s->name, p->n->name) == 0) { if (nproc-nstop >= MAXP) { printf("spin: too many processes (%d max)\n", MAXP); break; @@ -173,7 +193,7 @@ enable(Lextok *m) setparams(run, p, n); setlocals(run); /* after setparams */ return run->pid - Have_claim + Skip_claim; /* effective simu pid */ - } + } } return 0; /* process not found */ } @@ -208,26 +228,29 @@ start_claim(int n) RunList *r, *q = (RunList *) 0; for (p = rdy; p; p = p->nxt) - if (p->tn == n - && strcmp(p->n->name, ":never:") == 0) + if (p->tn == n && p->b == N_CLAIM) { runnable(p, 1, 1); goto found; } - printf("spin: couldn't find claim (ignored)\n"); + printf("spin: couldn't find claim %d (ignored)\n", n); + if (verbose&32) + for (p = rdy; p; p = p->nxt) + printf("\t%d = %s\n", p->tn, p->n->name); + Skip_claim = 1; goto done; found: /* move claim to far end of runlist, and reassign it pid 0 */ if (columns == 2) - { depth = 0; - pstext(0, "0::never:"); + { extern char Buf[]; + depth = 0; + sprintf(Buf, "%d:%s", 0, p->n->name); + pstext(0, Buf); for (r = run; r; r = r->nxt) - { if (!strcmp(r->n->name, ":never:")) - continue; - sprintf(Buf, "%d:%s", - r->pid+1, r->n->name); - pstext(r->pid+1, Buf); - } } + { if (r->b != N_CLAIM) + { sprintf(Buf, "%d:%s", r->pid+1, r->n->name); + pstext(r->pid+1, Buf); + } } } if (run->pid == 0) return; /* it is the first process started */ @@ -288,7 +311,7 @@ wrapup(int fini) nproc - Have_claim + Skip_claim, (xspin || nproc!=1)?"es":""); short_cut: - if (xspin) alldone(0); /* avoid an abort from xspin */ + if (s_trail || xspin) alldone(0); /* avoid an abort from xspin */ if (fini) alldone(1); } @@ -332,6 +355,24 @@ silent_moves(Element *e) return e; } +static int +x_can_run(void) /* the currently selected process in X can run */ +{ + if (X->prov && !eval(X->prov)) + { +if (0) printf("pid %d cannot run: not provided\n", X->pid); + return 0; + } + if (has_priority && !old_priority_rules) + { Lextok *n = nn(ZN, CONST, ZN, ZN); + n->val = X->pid; +if (0) printf("pid %d %s run (priority)\n", X->pid, pc_highest(n)?"can":"cannot"); + return pc_highest(n); + } +if (0) printf("pid %d can run\n", X->pid); + return 1; +} + static RunList * pickproc(RunList *Y) { SeqList *z; Element *has_else; @@ -343,7 +384,25 @@ pickproc(RunList *Y) return NULL; } if (!interactive || depth < jumpsteps) - { /* was: j = (int) Rand()%(nproc-nstop); */ + { if (has_priority && !old_priority_rules) /* new 6.3.2 */ + { j = Rand()%(nproc-nstop); + for (X = run; X; X = X->nxt) + { if (j-- <= 0) + break; + } + if (X == NULL) + { fatal("unexpected, pickproc", (char *)0); + } + j = nproc - nstop; + while (j-- > 0) + { if (x_can_run()) + { Y = X; + break; + } + X = (X->nxt)?X->nxt:run; + } + return Y; + } if (Priority_Sum < nproc-nstop) fatal("cannot happen - weights", (char *)0); j = (int) Rand()%Priority_Sum; @@ -354,6 +413,7 @@ pickproc(RunList *Y) X = X->nxt; if (!X) { Y = NULL; X = run; } } + } else { int only_choice = -1; int no_choice = 0, proc_no_ch, proc_k; @@ -365,8 +425,7 @@ try_more: for (X = run, k = 1; X; X = X->nxt) Choices[X->pid] = (short) k; - if (!X->pc - || (X->prov && !eval(X->prov))) + if (!X->pc || !x_can_run()) { if (X == run) Choices[X->pid] = 0; continue; @@ -457,9 +516,12 @@ try_more: for (X = run, k = 1; X; X = X->nxt) } else { char buf[256]; fflush(stdout); - scanf("%s", buf); + if (scanf("%64s", buf) == 0) + { printf("\tno input\n"); + goto try_again; + } j = -1; - if (isdigit(buf[0])) + if (isdigit((int) buf[0])) j = atoi(buf); else { if (buf[0] == 'q') @@ -483,6 +545,26 @@ try_more: for (X = run, k = 1; X; X = X->nxt) return Y; } +void +multi_claims(void) +{ ProcList *p, *q = NULL; + + if (nclaims > 1) + { printf(" the model contains %d never claims:", nclaims); + for (p = rdy; p; p = p->nxt) + { if (p->b == N_CLAIM) + { printf("%s%s", q?", ":" ", p->n->name); + q = p; + } } + printf("\n"); + printf(" only one claim is used in a verification run\n"); + printf(" choose which one with ./pan -a -N name (defaults to -N %s)\n", + q?q->n->name:"--"); + printf(" or use e.g.: spin -search -ltl %s %s\n", + q?q->n->name:"--", Fname?Fname->name:"filename"); + } +} + void sched(void) { Element *e; @@ -498,19 +580,33 @@ sched(void) dumplabels(); return; } + if (has_code && !analyze) + { printf("spin: warning: c_code fragments remain uninterpreted\n"); + printf(" in random simulations with spin; use ./pan -r instead\n"); + } if (has_enabled && u_sync > 0) { printf("spin: error, cannot use 'enabled()' in "); printf("models with synchronous channels.\n"); nr_errs++; } - if (analyze) + if (product) + { sync_product(); + alldone(0); + } + if (analyze && (!replay || has_code)) { gensrc(); + multi_claims(); return; - } else if (s_trail) + } + if (replay && !has_code) + { return; + } + if (s_trail) { match_trail(); return; } + if (claimproc) printf("warning: never claim not used in random simulation\n"); if (eventmap) @@ -543,9 +639,9 @@ sched(void) depth++; LastStep = ZE; oX = X; /* a rendezvous could change it */ go = 1; - if (X && X->prov && X->pc + if (X->pc && !(X->pc->status & D_ATOM) - && !eval(X->prov)) + && !x_can_run()) { if (!xspin && ((verbose&32) || (verbose&4))) { p_talk(X->pc, 1); printf("\t<>\n"); @@ -557,9 +653,10 @@ sched(void) && ((verbose&32) || (verbose&4))) { if (X == oX) if (!(e->status & D_ATOM) || (verbose&32)) /* no talking in d_steps */ - { p_talk(X->pc, 1); + { if (!LastStep) LastStep = X->pc; + /* A. Tanaka, changed order */ + p_talk(LastStep, 1); printf(" ["); - if (!LastStep) LastStep = X->pc; comment(stdout, LastStep->n, 0); printf("]\n"); } @@ -570,7 +667,8 @@ sched(void) if (xspin) printf("\n"); } - if (oX != X) + if (oX != X + || (X->pc->status & (ATOM|D_ATOM))) /* new 5.0 */ { e = silent_moves(e); notbeyond = 0; } @@ -587,10 +685,12 @@ sched(void) } } else { depth--; - if (oX->pc->status & D_ATOM) - non_fatal("stmnt in d_step blocks", (char *)0); - - if (X->pc->n->ntyp == '@' + if (oX->pc && (oX->pc->status & D_ATOM)) + { non_fatal("stmnt in d_step blocks", (char *)0); + } + if (X->pc + && X->pc->n + && X->pc->n->ntyp == '@' && X->pid == (nproc-nstop-1)) { if (X != run && Y != NULL) Y->nxt = X->nxt; @@ -610,14 +710,19 @@ sched(void) X = (X->nxt) ? X->nxt : run; } else { if (p_blocked(X->pid)) - { if (Tval) break; - Tval = 1; - if (depth >= jumpsteps) + { if (Tval && !has_stdin) + { break; + } + if (!Tval && depth >= jumpsteps) { oX = X; X = (RunList *) 0; /* to suppress indent */ dotag(stdout, "timeout\n"); X = oX; + Tval = 1; } } } } + + if (!run || !X) break; /* new 5.0 */ + Y = pickproc(X); notbeyond = 0; } @@ -662,7 +767,7 @@ complete_rendez(void) printf(" ["); comment(stdout, s_was->n, 0); printf("]\n"); - tmp = orun; orun = X; X = tmp; + tmp = orun; /* orun = X; */ X = tmp; if (!LastStep) LastStep = X->pc; p_talk(LastStep, 1); printf(" ["); @@ -692,25 +797,33 @@ addsymbol(RunList *r, Symbol *s) int i; for (t = r->symtab; t; t = t->next) - if (strcmp(t->name, s->name) == 0) + if (strcmp(t->name, s->name) == 0 + && (old_scope_rules + || strcmp((const char *)t->bscp, (const char *)s->bscp) == 0)) return; /* it's already there */ t = (Symbol *) emalloc(sizeof(Symbol)); t->name = s->name; t->type = s->type; t->hidden = s->hidden; + t->isarray = s->isarray; t->nbits = s->nbits; t->nel = s->nel; t->ini = s->ini; t->setat = depth; t->context = r->n; + + t->bscp = (unsigned char *) emalloc(strlen((const char *)s->bscp)+1); + strcpy((char *)t->bscp, (const char *)s->bscp); + if (s->type != STRUCT) { if (s->val) /* if already initialized, copy info */ { t->val = (int *) emalloc(s->nel*sizeof(int)); for (i = 0; i < s->nel; i++) t->val[i] = s->val[i]; } else - (void) checkvar(t, 0); /* initialize it */ + { (void) checkvar(t, 0); /* initialize it */ + } } else { if (s->Sval) fatal("saw preinitialized struct %s", s->name); @@ -759,7 +872,7 @@ oneparam(RunList *r, Lextok *t, Lextok *a, ProcList *p) if (!a) fatal("missing actual parameters: '%s'", p->n->name); - if (t->sym->nel != 1) + if (t->sym->nel > 1 || t->sym->isarray) fatal("array in parameter list, %s", t->sym->name); k = eval(a->lft); @@ -768,7 +881,7 @@ oneparam(RunList *r, Lextok *t, Lextok *a, ProcList *p) ft = Sym_typ(t); if (at != ft && (at == CHAN || ft == CHAN)) - { char buf[128], tag1[64], tag2[64]; + { char buf[256], tag1[64], tag2[64]; (void) sputtype(tag1, ft); (void) sputtype(tag2, at); sprintf(buf, "type-clash in params of %s(..), (%s<-> %s)", @@ -809,8 +922,11 @@ findloc(Symbol *s) return ZS; } for (r = X->symtab; r; r = r->next) - if (strcmp(r->name, s->name) == 0) - break; + { if (strcmp(r->name, s->name) == 0 + && (old_scope_rules + || strcmp((const char *)r->bscp, (const char *)s->bscp) == 0)) + { break; + } } if (!r) { addsymbol(X, s); r = X->symtab; @@ -878,7 +994,11 @@ whoruns(int lnr) printf(" -"); else printf("%2d", X->pid - Have_claim); - printf(" (%s) ", X->n->name); + if (old_priority_rules) + { printf(" (%s) ", X->n->name); + } else + { printf(" (%s:%d) ", X->n->name, X->priority); + } } static void @@ -895,6 +1015,7 @@ talk(RunList *r) void p_talk(Element *e, int lnr) { static int lastnever = -1; + static char nbuf[128]; int newnever = -1; if (e && e->n) @@ -918,9 +1039,22 @@ p_talk(Element *e, int lnr) whoruns(lnr); if (e) - { printf("line %3d %s (state %d)", + { if (e->n) + { char *ptr = e->n->fn->name; + char *qtr = nbuf; + while (*ptr != '\0') + { if (*ptr != '"') + { *qtr++ = *ptr; + } + ptr++; + } + *qtr = '\0'; + } else + { strcpy(nbuf, "-"); + } + printf("%s:%d (state %d)", + nbuf, e->n?e->n->ln:-1, - e->n?e->n->fn->name:"-", e->seqno); if (!xspin && ((e->status&ENDSTATE) || has_lab(e, 2))) /* 2=end */ @@ -943,8 +1077,9 @@ remotelab(Lextok *n) { fatal("remote ref to label '%s' inside d_step", n->sym->name); } - if ((i = find_lab(n->sym, n->lft->sym, 1)) == 0) - fatal("unknown labelname: %s", n->sym->name); + if ((i = find_lab(n->sym, n->lft->sym, 1)) == 0) /* remotelab */ + { fatal("unknown labelname: %s", n->sym->name); + } return i; } @@ -970,7 +1105,8 @@ remotevar(Lextok *n) } } if (prno < 0) - return 0; /* non-existing process */ + { return 0; /* non-existing process */ + } #if 0 i = nproc - nstop; for (Y = run; Y; Y = Y->nxt) @@ -978,7 +1114,7 @@ remotevar(Lextok *n) printf(" %s: i=%d, prno=%d, ->pid=%d\n", Y->n->name, i, prno, Y->pid); } #endif - i = nproc - nstop; + i = nproc - nstop + Skip_claim; /* 6.0: added Skip_claim */ for (Y = run; Y; Y = Y->nxt) if (--i == prno) { if (strcmp(Y->n->name, n->lft->sym->name) != 0) @@ -988,12 +1124,13 @@ remotevar(Lextok *n) } if (strcmp(n->sym->name, "_p") == 0) { if (Y->pc) - return Y->pc->seqno; + { return Y->pc->seqno; + } /* harmless, can only happen with -t */ return 0; } -#if 1 - /* new 4.0 allow remote variables */ + + /* check remote variables */ oX = X; X = Y; @@ -1001,17 +1138,20 @@ remotevar(Lextok *n) n->lft = n->rgt; os = n->sym; - n->sym = findloc(n->sym); - + if (!n->sym->context) + { n->sym->context = Y->n; + } + { int rs = old_scope_rules; + old_scope_rules = 1; /* 6.4.0 */ + n->sym = findloc(n->sym); + old_scope_rules = rs; + } 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-added); non_fatal("%s not found", n->sym->name); diff --git a/sys/src/cmd/spin/spin.h b/sys/src/cmd/spin/spin.h index 327ec6871..2ec8d3038 100644 --- a/sys/src/cmd/spin/spin.h +++ b/sys/src/cmd/spin/spin.h @@ -1,13 +1,10 @@ /***** spin: spin.h *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #ifndef SEEN_SPIN_H #define SEEN_SPIN_H @@ -15,6 +12,15 @@ #include #include #include +#if !defined(WIN32) && !defined(WIN64) + #include +#endif +#if !defined(PC) && !defined(_PLAN9) + #include +#endif + +enum { INIV, PUTV, LOGV }; /* used in pangen1.c */ +enum btypes { NONE, N_CLAIM, I_PROC, A_PROC, P_PROC, E_TRACE, N_TRACE }; typedef struct Lextok { unsigned short ntyp; /* node type */ @@ -22,6 +28,7 @@ typedef struct Lextok { int val; /* value attribute */ int ln; /* line number */ int indstep; /* part of d_step sequence */ + int uiid; /* inline id, if non-zero */ struct Symbol *fn; /* file name */ struct Symbol *sym; /* symbol reference */ struct Sequence *sq; /* sequence */ @@ -54,6 +61,9 @@ typedef struct Symbol { 64=treat as if local; 128=read at least once */ unsigned char colnr; /* for use with xspin during simulation */ + unsigned char isarray; /* set if decl specifies array bound */ + unsigned char *bscp; /* block scope */ + int sc; /* scope seq no -- set only for proctypes */ int nbits; /* optional width specifier */ int nel; /* 1 if scalar, >1 if array */ int setat; /* last depth value changed */ @@ -124,7 +134,7 @@ typedef struct Element { int merge_single; short merge_in; /* nr of incoming edges */ short merge_mark; /* state was generated in merge sequence */ - unsigned char status; /* used by analyzer generator */ + unsigned int status; /* used by analyzer generator */ struct FSM_use *dead; /* optional dead variable list */ struct SeqList *sub; /* subsequences, for compounds */ struct SeqList *esc; /* zero or more escape sequences */ @@ -136,6 +146,7 @@ typedef struct Sequence { Element *frst; Element *last; /* links onto continuations */ Element *extent; /* last element in original */ + int minel; /* minimum Seqno, set and used only in guided.c */ int maxel; /* 1+largest id in sequence */ } Sequence; @@ -148,6 +159,7 @@ typedef struct Label { Symbol *s; Symbol *c; Element *e; + int uiid; /* non-zero if label appears in an inline */ int visible; /* label referenced in claim (slice relevant) */ struct Label *nxt; } Label; @@ -157,11 +169,17 @@ typedef struct Lbreak { struct Lbreak *nxt; } Lbreak; +typedef struct L_List { + Lextok *n; + struct L_List *nxt; +} L_List; + typedef struct RunList { Symbol *n; /* name */ int tn; /* ordinal of type */ int pid; /* process id */ int priority; /* for simulations only */ + enum btypes b; /* the type of process */ Element *pc; /* current stmnt */ Sequence *ps; /* used by analyzer generator */ Lextok *prov; /* provided clause */ @@ -174,11 +192,19 @@ typedef struct ProcList { Lextok *p; /* parameters */ Sequence *s; /* body */ Lextok *prov; /* provided clause */ + enum btypes b; /* e.g., claim, trace, proc */ short tn; /* ordinal number */ - short det; /* deterministic */ + unsigned char det; /* deterministic */ + unsigned char unsafe; /* contains global var inits */ + unsigned char priority; /* process priority, if any */ struct ProcList *nxt; /* linked list */ } ProcList; +typedef struct QH { + int n; + struct QH *nxt; +} QH; + typedef Lextok *Lexptr; #define YYSTYPE Lexptr @@ -194,7 +220,8 @@ typedef Lextok *Lexptr; #define DONE2 16 /* used in putcode and main*/ #define D_ATOM 32 /* deterministic atomic */ #define ENDSTATE 64 /* normal endstate */ -#define CHECK2 128 +#define CHECK2 128 /* status bits for remote ref check */ +#define CHECK3 256 /* status bits for atomic jump check */ #define Nhash 255 /* slots in symbol hash-table */ @@ -216,18 +243,24 @@ typedef Lextok *Lexptr; #define SOMETHINGBIG 65536 #define RATHERSMALL 512 +#define MAXSCOPESZ 1024 #ifndef max -#define max(a,b) (((a)<(b)) ? (b) : (a)) + #define max(a,b) (((a)<(b)) ? (b) : (a)) #endif -enum { INIV, PUTV, LOGV }; /* for pangen[14].c */ +#ifdef PC + #define MFLAGS "wb" +#else + #define MFLAGS "w" +#endif /***** prototype definitions *****/ Element *eval_sub(Element *); Element *get_lab(Lextok *, int); -Element *huntele(Element *, int, int); +Element *huntele(Element *, unsigned int, int); Element *huntstart(Element *); +Element *mk_skip(void); Element *target(Element *); Lextok *do_unless(Lextok *, Lextok *); @@ -238,8 +271,9 @@ Lextok *nn(Lextok *, int, Lextok *, Lextok *); Lextok *rem_lab(Symbol *, Lextok *, Symbol *); Lextok *rem_var(Symbol *, Lextok *, Symbol *, Lextok *); Lextok *tail_add(Lextok *, Lextok *); +Lextok *return_statement(Lextok *); -ProcList *ready(Symbol *, Lextok *, Sequence *, int, Lextok *); +ProcList *ready(Symbol *, Lextok *, Sequence *, int, Lextok *, enum btypes); SeqList *seqlist(Sequence *, SeqList *); Sequence *close_seq(int); @@ -250,7 +284,8 @@ Symbol *has_lab(Element *, int); Symbol *lookup(char *); Symbol *prep_inline(Symbol *, Lextok *); -char *emalloc(int); +char *put_inline(FILE *, char *); +char *emalloc(size_t); long Rand(void); int any_oper(Lextok *, int); @@ -258,6 +293,7 @@ int any_undo(Lextok *); int c_add_sv(FILE *); int cast_val(int, int, int); int checkvar(Symbol *, int); +int check_track(Lextok *); int Cnt_flds(Lextok *); int cnt_mpars(Lextok *); int complete_rendez(void); @@ -274,12 +310,14 @@ int has_typ(Lextok *, int); int in_bound(Symbol *, int); int interprint(FILE *, Lextok *); int printm(FILE *, Lextok *); +int is_inline(void); int ismtype(char *); int isproctype(char *); int isutype(char *); int Lval_struct(Lextok *, Symbol *, int, int); int main(int, char **); int pc_value(Lextok *); +int pid_is_claim(int); int proper_enabler(Lextok *); int putcode(FILE *, Sequence *, Element *, int, int, int); int q_is_sync(Lextok *); @@ -298,7 +336,6 @@ int Sym_typ(Lextok *); int tl_main(int, char *[]); int Width_set(int *, int, Lextok *); int yyparse(void); -int yywrap(void); int yylex(void); void AST_track(Lextok *, int); @@ -309,7 +346,6 @@ 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 *); @@ -321,6 +357,7 @@ void check_param_count(int, Lextok *); void checkrun(Symbol *, int); void comment(FILE *, Lextok *, int); void cross_dsteps(Lextok *, Lextok *); +void disambiguate(void); void doq(Symbol *, int, RunList *); void dotag(FILE *, char *); void do_locinits(FILE *); @@ -344,20 +381,22 @@ void genunio(void); void ini_struct(Symbol *); void loose_ends(void); void make_atomic(Sequence *, int); +void mark_last(void); 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 ntimes(FILE *, int, int, const char *c[]); void open_seq(int); void p_talk(Element *, int); -void pickup_inline(Symbol *, Lextok *); +void pickup_inline(Symbol *, Lextok *, Lextok *); void plunk_c_decls(FILE *); void plunk_c_fcts(FILE *); void plunk_expr(FILE *, char *); -void plunk_inline(FILE *, char *, int); +void plunk_inline(FILE *, char *, int, int); void prehint(Symbol *); void preruse(FILE *, Lextok *); +void pretty_print(void); void prune_opts(Lextok *); void pstext(int, char *); void pushbreak(void); @@ -383,17 +422,23 @@ void start_claim(int); void struct_name(Lextok *, Symbol *, int, char *); void symdump(void); void symvar(Symbol *); +void sync_product(void); void trackchanuse(Lextok *, Lextok *, int); void trackvar(Lextok *, Lextok *); void trackrun(Lextok *); -void trapwonly(Lextok *, char *); /* spin.y and main.c */ +void trapwonly(Lextok * /* , char * */); /* spin.y and main.c */ void typ2c(Symbol *); void typ_ck(int, int, char *); void undostmnt(Lextok *, int); void unrem_Seq(void); void unskip(int); -void varcheck(Element *, Element *); void whoruns(int); void wrapup(int); void yyerror(char *, ...); + +extern int unlink(const char *); + +#define TMP_FILE1 "._s_p_i_n_" +#define TMP_FILE2 "._n_i_p_s_" + #endif diff --git a/sys/src/cmd/spin/spin.y b/sys/src/cmd/spin/spin.y index 20c391a89..8647cbc31 100644 --- a/sys/src/cmd/spin/spin.y +++ b/sys/src/cmd/spin/spin.y @@ -1,47 +1,69 @@ /***** spin: spin.y *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ %{ #include "spin.h" +#include +#ifndef PC +#include +#endif #include -#define YYDEBUG 0 +#define YYMAXDEPTH 20000 /* default is 10000 */ +#define YYDEBUG 0 #define Stop nn(ZN,'@',ZN,ZN) +#define PART0 "place initialized declaration of " +#define PART1 "place initialized chan decl of " +#define PART2 " at start of proctype " + +static Lextok *ltl_to_string(Lextok *); 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 Lextok *for_body(Lextok *, int); +extern void for_setup(Lextok *, Lextok *, Lextok *); +extern Lextok *for_index(Lextok *, Lextok *); +extern Lextok *sel_index(Lextok *, Lextok *, Lextok *); +extern void keep_track_off(Lextok *); +extern void safe_break(void); +extern void restore_break(void); +extern int u_sync, u_async, dumptab, scope_level; +extern int initialization_ok; +extern short has_sorted, has_random, has_enabled, has_pcvalue, has_np, has_priority; +extern short has_code, has_state, has_ltl, has_io; extern void count_runs(Lextok *); extern void no_internals(Lextok *); extern void any_runs(Lextok *); +extern void explain(int); +extern void ltl_list(char *, char *); extern void validref(Lextok *, Lextok *); +extern void sanity_check(Lextok *); extern char yytext[]; int Mpars = 0; /* max nr of message parameters */ -int runsafe = 1; /* 1 if all run stmnts are in init */ +int nclaims = 0; /* nr of never claims */ +int ltl_mode = 0; /* set when parsing an ltl formula */ int Expand_Ok = 0, realread = 1, IArgs = 0, NamesNotAdded = 0; +int in_for = 0, in_seq = 0, par_cnt = 0; +int dont_simplify = 0; char *claimproc = (char *) 0; char *eventmap = (char *) 0; -static int Embedded = 0, inEventMap = 0, has_ini = 0; +static char *ltl_name; +static int Embedded = 0, inEventMap = 0, has_ini = 0; %} -%token ASSERT PRINT PRINTM +%token ASSERT PRINT PRINTM PREPROC %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 -%token IF FI DO OD SEP +%token RUN LEN ENABLED SET_P GET_P EVAL PC_VAL +%token TYPEDEF MTYPE INLINE RETURN LABEL OF +%token GOTO BREAK ELSE SEMI ARROW +%token IF FI DO OD FOR SELECT IN SEP DOTDOT %token ATOMIC NON_ATOMIC D_STEP UNLESS %token TIMEOUT NONPROGRESS %token ACTIVE PROCTYPE D_PROCTYPE @@ -50,12 +72,16 @@ static int Embedded = 0, inEventMap = 0, has_ini = 0; %token FULL EMPTY NFULL NEMPTY %token CONST TYPE XU /* val */ %token NAME UNAME PNAME INAME /* sym */ -%token STRING CLAIM TRACE INIT /* sym */ +%token STRING CLAIM TRACE INIT LTL /* sym */ %right ASGN %left SND O_SND RCV R_RCV /* SND doubles as boolean negation */ +%left IMPLIES EQUIV /* ltl */ %left OR %left AND +%left ALWAYS EVENTUALLY /* ltl */ +%left UNTIL WEAK_UNTIL RELEASE /* ltl */ +%right NEXT /* ltl */ %left '|' %left '^' %left '&' @@ -81,17 +107,25 @@ units : unit unit : proc /* proctype { } */ | init /* init { } */ | claim /* never claim */ + | ltl /* ltl formula */ | events /* event assertions */ | one_decl /* variables, chans */ | utype /* user defined types */ | c_fcts /* c functions etc. */ | ns /* named sequence */ - | SEMI /* optional separator */ + | semi /* optional separator */ | error ; +l_par : '(' { par_cnt++; } + ; + +r_par : ')' { par_cnt--; } + ; + + proc : inst /* optional instantiator */ - proctype NAME { + proctype NAME { setptype($3, PROCTYPE, ZN); setpname($3); context = $3->sym; @@ -99,20 +133,29 @@ proc : inst /* optional instantiator */ Expand_Ok++; /* expand struct names in decl */ has_ini = 0; } - '(' decl ')' { Expand_Ok--; + l_par decl r_par { Expand_Ok--; if (has_ini) fatal("initializer in parameter list", (char *) 0); } Opt_priority Opt_enabler body { ProcList *rl; - rl = ready($3->sym, $6, $11->sq, $2->val, $10); if ($1 != ZN && $1->val > 0) { int j; + rl = ready($3->sym, $6, $11->sq, $2->val, $10, A_PROC); for (j = 0; j < $1->val; j++) - runnable(rl, $9?$9->val:1, 1); + { runnable(rl, $9?$9->val:1, 1); announce(":root:"); + } if (dumptab) $3->sym->ini = $1; + } else + { rl = ready($3->sym, $6, $11->sq, $2->val, $10, P_PROC); + } + if (rl && has_ini == 1) /* global initializations, unsafe */ + { /* printf("proctype %s has initialized data\n", + $3->sym->name); + */ + rl->unsafe = 1; } context = ZS; } @@ -124,7 +167,7 @@ proctype: PROCTYPE { $$ = nn(ZN,CONST,ZN,ZN); $$->val = 0; } inst : /* empty */ { $$ = ZN; } | ACTIVE { $$ = nn(ZN,CONST,ZN,ZN); $$->val = 1; } - | ACTIVE '[' CONST ']' { + | ACTIVE '[' const_expr ']' { $$ = nn(ZN,CONST,ZN,ZN); $$->val = $3->val; if ($3->val > 255) non_fatal("max nr of processes is 255\n", ""); @@ -133,10 +176,10 @@ inst : /* empty */ { $$ = ZN; } $$ = nn(ZN,CONST,ZN,ZN); $$->val = 0; if (!$3->sym->type) - non_fatal("undeclared variable %s", + fatal("undeclared variable %s", $3->sym->name); else if ($3->sym->ini->ntyp != CONST) - non_fatal("need constant initializer for %s\n", + fatal("need constant initializer for %s\n", $3->sym->name); else $$->val = $3->sym->ini->val; @@ -146,41 +189,84 @@ inst : /* empty */ { $$ = ZN; } init : INIT { context = $1->sym; } Opt_priority body { ProcList *rl; - rl = ready(context, ZN, $4->sq, 0, ZN); + rl = ready(context, ZN, $4->sq, 0, ZN, I_PROC); runnable(rl, $3?$3->val:1, 1); announce(":root:"); context = ZS; } ; -claim : CLAIM { context = $1->sym; - if (claimproc) - non_fatal("claim %s redefined", claimproc); +ltl : LTL optname2 { ltl_mode = 1; ltl_name = $2->sym->name; } + ltl_body { if ($4) ltl_list($2->sym->name, $4->sym->name); + ltl_mode = 0; has_ltl = 1; + } + ; + +ltl_body: '{' full_expr OS '}' { $$ = ltl_to_string($2); } + | error { $$ = NULL; } + ; + +claim : CLAIM optname { if ($2 != ZN) + { $1->sym = $2->sym; /* new 5.3.0 */ + } + nclaims++; + context = $1->sym; + if (claimproc && !strcmp(claimproc, $1->sym->name)) + { fatal("claim %s redefined", claimproc); + } claimproc = $1->sym->name; } - body { (void) ready($1->sym, ZN, $3->sq, 0, ZN); + body { (void) ready($1->sym, ZN, $4->sq, 0, ZN, N_CLAIM); context = ZS; } ; +optname : /* empty */ { char tb[32]; + memset(tb, 0, 32); + sprintf(tb, "never_%d", nclaims); + $$ = nn(ZN, NAME, ZN, ZN); + $$->sym = lookup(tb); + } + | NAME { $$ = $1; } + ; + +optname2 : /* empty */ { char tb[32]; static int nltl = 0; + memset(tb, 0, 32); + sprintf(tb, "ltl_%d", nltl++); + $$ = nn(ZN, NAME, ZN, ZN); + $$->sym = lookup(tb); + } + | NAME { $$ = $1; } + ; + events : TRACE { context = $1->sym; if (eventmap) non_fatal("trace %s redefined", eventmap); eventmap = $1->sym->name; inEventMap++; } - body { (void) ready($1->sym, ZN, $3->sq, 0, ZN); + body { + if (strcmp($1->sym->name, ":trace:") == 0) + { (void) ready($1->sym, ZN, $3->sq, 0, ZN, E_TRACE); + } else + { (void) ready($1->sym, ZN, $3->sq, 0, ZN, N_TRACE); + } context = ZS; inEventMap--; } ; -utype : TYPEDEF NAME { if (context) - fatal("typedef %s must be global", - $2->sym->name); +utype : TYPEDEF NAME '{' { if (context) + { fatal("typedef %s must be global", + $2->sym->name); + } owner = $2->sym; + in_seq = $1->ln; + } + decl_lst '}' { setuname($5); + owner = ZS; + in_seq = 0; } - '{' decl_lst '}' { setuname($5); owner = ZS; } ; nm : NAME { $$ = $1; } @@ -190,8 +276,8 @@ nm : NAME { $$ = $1; } } ; -ns : INLINE nm '(' { NamesNotAdded++; } - args ')' { prep_inline($2->sym, $5); +ns : INLINE nm l_par { NamesNotAdded++; } + args r_par { prep_inline($2->sym, $5); NamesNotAdded--; } ; @@ -227,6 +313,8 @@ ccode : C_CODE { Symbol *s; NamesNotAdded--; $$ = nn(ZN, C_CODE, ZN, ZN); $$->sym = s; + $$->ln = $1->ln; + $$->fn = $1->fn; has_code = 1; } | C_DECL { Symbol *s; @@ -236,23 +324,37 @@ ccode : C_CODE { Symbol *s; s->type = CODE_DECL; $$ = nn(ZN, C_CODE, ZN, ZN); $$->sym = s; + $$->ln = $1->ln; + $$->fn = $1->fn; has_code = 1; } ; cexpr : C_EXPR { Symbol *s; NamesNotAdded++; s = prep_inline(ZS, ZN); +/* if context is 0 this was inside an ltl formula + mark the last inline added to seqnames */ + if (!context) + { mark_last(); + } NamesNotAdded--; $$ = nn(ZN, C_EXPR, ZN, ZN); $$->sym = s; + $$->ln = $1->ln; + $$->fn = $1->fn; no_side_effects(s->name); has_code = 1; } ; -body : '{' { open_seq(1); } +body : '{' { open_seq(1); in_seq = $1->ln; } sequence OS { add_seq(Stop); } - '}' { $$->sq = close_seq(0); } + '}' { $$->sq = close_seq(0); in_seq = 0; + if (scope_level != 0) + { non_fatal("missing '}' ?", 0); + scope_level = 0; + } + } ; sequence: step { if ($1) add_seq($1); } @@ -264,7 +366,11 @@ step : one_decl { $$ = 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); } + | stmnt UNLESS { if ($1->ntyp == DO) { safe_break(); } } + stmnt { if ($1->ntyp == DO) { restore_break(); } + $$ = do_unless($1, $4); + } + | error { printf("Not a Step\n"); } ; vis : /* empty */ { $$ = ZN; } @@ -277,7 +383,9 @@ asgn: /* empty */ | ASGN ; -one_decl: vis TYPE var_list { setptype($3, $2->val, $1); $$ = $3; } +one_decl: vis TYPE var_list { setptype($3, $2->val, $1); + $$ = $3; + } | vis UNAME var_list { setutype($3, $2->sym, $1); $$ = expand($3, Expand_Ok); } @@ -310,26 +418,76 @@ var_list: ivar { $$ = nn($1, TYPE, ZN, ZN); } | ivar ',' var_list { $$ = nn($1, TYPE, ZN, $3); } ; +c_list : CONST { $1->ntyp = CONST; $$ = $1; } + | CONST ',' c_list { $1->ntyp = CONST; $$ = nn($1, ',', $1, $3); } + ; + ivar : vardcl { $$ = $1; $1->sym->ini = nn(ZN,CONST,ZN,ZN); $1->sym->ini->val = 0; + if (!initialization_ok) + { Lextok *zx, *xz; + zx = nn(ZN, NAME, ZN, ZN); + zx->sym = $1->sym; + xz = nn(zx, ASGN, zx, $1->sym->ini); + keep_track_off(xz); + /* make sure zx doesnt turn out to be a STRUCT later */ + add_seq(xz); + } } - | vardcl ASGN expr { $1->sym->ini = $3; $$ = $1; - trackvar($1,$3); has_ini = 1; + | vardcl ASGN '{' c_list '}' { + if (!$1->sym->isarray) + fatal("%s must be an array", $1->sym->name); + $$ = $1; + $1->sym->ini = $4; + has_ini = 1; + $1->sym->hidden |= (4|8); /* conservative */ + if (!initialization_ok) + { Lextok *zx = nn(ZN, NAME, ZN, ZN); + zx->sym = $1->sym; + add_seq(nn(zx, ASGN, zx, $4)); + } + } + | vardcl ASGN expr { $$ = $1; + $1->sym->ini = $3; + if ($3->ntyp == CONST + || ($3->ntyp == NAME && $3->sym->context)) + { has_ini = 2; /* local init */ + } else + { has_ini = 1; /* possibly global */ + } + trackvar($1, $3); + if (any_oper($3, RUN)) + { fatal("cannot use 'run' in var init, saw", (char *) 0); + } + nochan_manip($1, $3, 0); + no_internals($1); + if (!initialization_ok) + { Lextok *zx = nn(ZN, NAME, ZN, ZN); + zx->sym = $1->sym; + add_seq(nn(zx, ASGN, zx, $3)); + } } | vardcl ASGN ch_init { $1->sym->ini = $3; $$ = $1; has_ini = 1; + if (!initialization_ok) + { non_fatal(PART1 "'%s'" PART2, $1->sym->name); + } } ; -ch_init : '[' CONST ']' OF - '{' typ_list '}' { if ($2->val) u_async++; - else u_sync++; +ch_init : '[' const_expr ']' OF + '{' typ_list '}' { if ($2->val) + u_async++; + else + u_sync++; { int i = cnt_mpars($6); Mpars = max(Mpars, i); } $$ = nn(ZN, CHAN, ZN, $6); $$->val = $2->val; + $$->ln = $1->ln; + $$->fn = $1->fn; } ; @@ -342,13 +500,33 @@ vardcl : NAME { $1->sym->nel = 1; $$ = $1; } } $1->sym->nel = 1; $$ = $1; } - | NAME '[' CONST ']' { $1->sym->nel = $3->val; $$ = $1; } + | NAME '[' const_expr ']' { $1->sym->nel = $3->val; $1->sym->isarray = 1; $$ = $1; } + | NAME '[' NAME ']' { /* make an exception for an initialized scalars */ + $$ = nn(ZN, CONST, ZN, ZN); + fprintf(stderr, "spin: %s:%d, warning: '%s' in array bound ", + $1->fn->name, $1->ln, $3->sym->name); + if ($3->sym->ini->val > 0) + { fprintf(stderr, "evaluated as %d\n", $3->sym->ini->val); + $$->val = $3->sym->ini->val; + } else + { fprintf(stderr, "evaluated as 8 by default (to avoid zero)\n"); + $$->val = 8; + } + $1->sym->nel = $$->val; + $1->sym->isarray = 1; + $$ = $1; + } ; varref : cmpnd { $$ = mk_explicit($1, Expand_Ok, NAME); } ; -pfld : NAME { $$ = nn($1, NAME, ZN, ZN); } +pfld : NAME { $$ = nn($1, NAME, ZN, ZN); + if ($1->sym->isarray && !in_for) + { non_fatal("missing array index for '%s'", + $1->sym->name); + } + } | NAME { owner = ZS; } '[' expr ']' { $$ = nn($1, NAME, $4, ZN); } ; @@ -363,7 +541,7 @@ cmpnd : pfld { Embedded++; Embedded--; if (!Embedded && !NamesNotAdded && !$1->sym->type) - non_fatal("undeclared variable: %s", + fatal("undeclared variable: %s", $1->sym->name); if ($3) validref($1, $3->lft); owner = ZS; @@ -374,13 +552,21 @@ sfld : /* empty */ { $$ = ZN; } | '.' cmpnd %prec DOT { $$ = nn(ZN, '.', $2, ZN); } ; -stmnt : Special { $$ = $1; } - | Stmnt { $$ = $1; - if (inEventMap) - non_fatal("not an event", (char *)0); +stmnt : Special { $$ = $1; initialization_ok = 0; } + | Stmnt { $$ = $1; initialization_ok = 0; + if (inEventMap) non_fatal("not an event", (char *)0); } ; +for_pre : FOR l_par { in_for = 1; } + varref { trapwonly($4 /*, "for" */); + pushbreak(); /* moved up */ + $$ = $4; + } + ; + +for_post: '{' sequence OS '}' ; + Special : varref RCV { Expand_Ok++; } rargs { Expand_Ok--; has_io++; $$ = nn($1, 'r', $1, $4); @@ -392,13 +578,30 @@ Special : varref RCV { Expand_Ok++; } $$->val=0; trackchanuse($4, ZN, 'S'); any_runs($4); } + | for_pre ':' expr DOTDOT expr r_par { + for_setup($1, $3, $5); in_for = 0; + } + for_post { $$ = for_body($1, 1); + } + | for_pre IN varref r_par { $$ = for_index($1, $3); in_for = 0; + } + for_post { $$ = for_body($5, 1); + } + | SELECT l_par varref ':' expr DOTDOT expr r_par { + trapwonly($3 /*, "select" */); + $$ = sel_index($3, $5, $7); + } | IF options FI { $$ = nn($1, IF, ZN, ZN); $$->sl = $2->sl; + $$->ln = $1->ln; + $$->fn = $1->fn; prune_opts($$); } | DO { pushbreak(); } options OD { $$ = nn($1, DO, ZN, ZN); $$->sl = $3->sl; + $$->ln = $1->ln; + $$->fn = $1->fn; prune_opts($$); } | BREAK { $$ = nn(ZN, GOTO, ZN, ZN); @@ -420,9 +623,22 @@ Special : varref RCV { Expand_Ok++; } } $1->sym->type = LABEL; } + | NAME ':' { $$ = nn($1, ':',ZN,ZN); + if ($1->sym->type != 0 + && $1->sym->type != LABEL) { + non_fatal("bad label-name %s", + $1->sym->name); + } + $$->lft = nn(ZN, 'c', nn(ZN,CONST,ZN,ZN), ZN); + $$->lft->lft->val = 1; /* skip */ + $1->sym->type = LABEL; + } + | error { $$ = nn(ZN, 'c', nn(ZN,CONST,ZN,ZN), ZN); + $$->lft->val = 1; /* skip */ + } ; -Stmnt : varref ASGN expr { $$ = nn($1, ASGN, $1, $3); +Stmnt : varref ASGN full_expr { $$ = nn($1, ASGN, $1, $3); trackvar($1, $3); nochan_manip($1, $3, 0); no_internals($1); @@ -443,10 +659,11 @@ Stmnt : varref ASGN expr { $$ = nn($1, ASGN, $1, $3); if ($1->sym->type == CHAN) fatal("arithmetic on chan id's", (char *)0); } - | PRINT '(' STRING { realread = 0; } - prargs ')' { $$ = nn($3, PRINT, $5, ZN); realread = 1; } - | PRINTM '(' varref ')' { $$ = nn(ZN, PRINTM, $3, ZN); } - | PRINTM '(' CONST ')' { $$ = nn(ZN, PRINTM, $3, ZN); } + | SET_P l_par two_args r_par { $$ = nn(ZN, SET_P, $3, ZN); has_priority++; } + | PRINT l_par STRING { realread = 0; } + prargs r_par { $$ = nn($3, PRINT, $5, ZN); realread = 1; } + | PRINTM l_par varref r_par { $$ = nn(ZN, PRINTM, $3, ZN); } + | PRINTM l_par CONST r_par { $$ = nn(ZN, PRINTM, $3, ZN); } | ASSERT full_expr { $$ = nn(ZN, ASSERT, $2, ZN); AST_track($2, 0); } | ccode { $$ = $1; } | varref R_RCV { Expand_Ok++; } @@ -480,21 +697,40 @@ Stmnt : varref ASGN expr { $$ = nn($1, ASGN, $1, $3); | ATOMIC '{' { open_seq(0); } sequence OS '}' { $$ = nn($1, ATOMIC, ZN, ZN); $$->sl = seqlist(close_seq(3), 0); - make_atomic($$->sl->this, 0); + $$->ln = $1->ln; + $$->fn = $1->fn; + make_atomic($$->sl->this, 0); } - | D_STEP '{' { open_seq(0); rem_Seq(); } + | D_STEP '{' { open_seq(0); + rem_Seq(); + } sequence OS '}' { $$ = nn($1, D_STEP, ZN, ZN); $$->sl = seqlist(close_seq(4), 0); + $$->ln = $1->ln; + $$->fn = $1->fn; make_atomic($$->sl->this, D_ATOM); unrem_Seq(); } | '{' { open_seq(0); } sequence OS '}' { $$ = nn(ZN, NON_ATOMIC, ZN, ZN); $$->sl = seqlist(close_seq(5), 0); + $$->ln = $1->ln; + $$->fn = $1->fn; } | INAME { IArgs++; } - '(' args ')' { pickup_inline($1->sym, $4); IArgs--; } + l_par args r_par { initialization_ok = 0; + pickup_inline($1->sym, $4, ZN); + IArgs--; + } Stmnt { $$ = $7; } + + | varref ASGN INAME { IArgs++; } + l_par args r_par { initialization_ok = 0; + pickup_inline($3->sym, $6, $1); + IArgs--; + } + Stmnt { $$ = $9; } + | RETURN full_expr { $$ = return_statement($2); } ; options : option { $$->sl = seqlist($1->sq, 0); } @@ -503,22 +739,39 @@ options : option { $$->sl = seqlist($1->sq, 0); } option : SEP { open_seq(0); } sequence OS { $$ = nn(ZN,0,ZN,ZN); - $$->sq = close_seq(6); } + $$->sq = close_seq(6); + $$->ln = $1->ln; + $$->fn = $1->fn; + } ; OS : /* empty */ - | SEMI { /* redundant semi at end of sequence */ } + | semi { /* redundant semi at end of sequence */ } ; -MS : SEMI { /* at least one semi-colon */ } - | MS SEMI { /* but more are okay too */ } +semi : SEMI + | ARROW + ; + +MS : semi { /* at least one semi-colon */ } + | MS semi { /* but more are okay too */ } ; aname : NAME { $$ = $1; } | PNAME { $$ = $1; } ; -expr : '(' expr ')' { $$ = $2; } +const_expr: CONST { $$ = $1; } + | '-' const_expr %prec UMIN { $$ = $2; $$->val = -($2->val); } + | l_par const_expr r_par { $$ = $2; } + | const_expr '+' const_expr { $$ = $1; $$->val = $1->val + $3->val; } + | const_expr '-' const_expr { $$ = $1; $$->val = $1->val - $3->val; } + | const_expr '*' const_expr { $$ = $1; $$->val = $1->val * $3->val; } + | const_expr '/' const_expr { $$ = $1; $$->val = $1->val / $3->val; } + | const_expr '%' const_expr { $$ = $1; $$->val = $1->val % $3->val; } + ; + +expr : l_par expr r_par { $$ = $2; } | expr '+' expr { $$ = nn(ZN, '+', $1, $3); } | expr '-' expr { $$ = nn(ZN, '-', $1, $3); } | expr '*' expr { $$ = nn(ZN, '*', $1, $3); } @@ -541,28 +794,25 @@ expr : '(' expr ')' { $$ = $2; } | '-' expr %prec UMIN { $$ = nn(ZN, UMIN, $2, ZN); } | SND expr %prec NEG { $$ = nn(ZN, '!', $2, ZN); } - | '(' expr SEMI expr ':' expr ')' { + | l_par expr ARROW expr ':' expr r_par { $$ = nn(ZN, OR, $4, $6); $$ = nn(ZN, '?', $2, $$); } | RUN aname { Expand_Ok++; if (!context) - fatal("used 'run' outside proctype", + fatal("used 'run' outside proctype", (char *) 0); - if (strcmp(context->name, ":init:") != 0) - runsafe = 0; } - '(' args ')' + l_par args r_par Opt_priority { Expand_Ok--; $$ = nn($2, RUN, $5, ZN); - $$->val = ($7) ? $7->val : 1; + $$->val = ($7) ? $7->val : 0; trackchanuse($5, $2, 'A'); trackrun($$); } - | LEN '(' varref ')' { $$ = nn($3, LEN, $3, ZN); } - | ENABLED '(' expr ')' { $$ = nn(ZN, ENABLED, $3, ZN); - has_enabled++; - } + | LEN l_par varref r_par { $$ = nn($3, LEN, $3, ZN); } + | ENABLED l_par expr r_par { $$ = nn(ZN, ENABLED, $3, ZN); has_enabled++; } + | GET_P l_par expr r_par { $$ = nn(ZN, GET_P, $3, ZN); has_priority++; } | varref RCV { Expand_Ok++; } '[' rargs ']' { Expand_Ok--; has_io++; $$ = nn($1, 'R', $1, $5); @@ -572,7 +822,7 @@ expr : '(' expr ')' { $$ = $2; } $$ = nn($1, 'R', $1, $5); $$->val = has_random = 1; } - | varref { $$ = $1; trapwonly($1, "varref"); } + | varref { $$ = $1; trapwonly($1 /*, "varref" */); } | cexpr { $$ = $1; } | CONST { $$ = nn(ZN,CONST,ZN,ZN); $$->ismtyp = $1->ismtyp; @@ -582,7 +832,7 @@ expr : '(' expr ')' { $$ = $2; } | NONPROGRESS { $$ = nn(ZN,NONPROGRESS, ZN, ZN); has_np++; } - | PC_VAL '(' expr ')' { $$ = nn(ZN, PC_VAL, $3, ZN); + | PC_VAL l_par expr r_par { $$ = nn(ZN, PC_VAL, $3, ZN); has_pcvalue++; } | PNAME '[' expr ']' '@' NAME @@ -591,18 +841,51 @@ expr : '(' expr ')' { $$ = $2; } { $$ = 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); } + | ltl_expr { $$ = $1; /* sanity_check($1); */ } ; Opt_priority: /* none */ { $$ = ZN; } - | PRIORITY CONST { $$ = $2; } + | PRIORITY CONST { $$ = $2; has_priority++; } ; full_expr: expr { $$ = $1; } - | Expr { $$ = $1; } + | Expr { $$ = $1; } + ; + +ltl_expr: expr UNTIL expr { $$ = nn(ZN, UNTIL, $1, $3); } + | expr RELEASE expr { $$ = nn(ZN, RELEASE, $1, $3); } + | expr WEAK_UNTIL expr { $$ = nn(ZN, ALWAYS, $1, ZN); + $$ = nn(ZN, OR, $$, nn(ZN, UNTIL, $1, $3)); + } + | expr IMPLIES expr { + $$ = nn(ZN, '!', $1, ZN); + $$ = nn(ZN, OR, $$, $3); + } + | expr EQUIV expr { $$ = nn(ZN, EQUIV, $1, $3); } + | NEXT expr %prec NEG { $$ = nn(ZN, NEXT, $2, ZN); } + | ALWAYS expr %prec NEG { $$ = nn(ZN, ALWAYS,$2, ZN); } + | EVENTUALLY expr %prec NEG { $$ = nn(ZN, EVENTUALLY, $2, ZN); } + ; + + /* an Expr cannot be negated - to protect Probe expressions */ +Expr : Probe { $$ = $1; } + | l_par Expr r_par { $$ = $2; } + | Expr AND Expr { $$ = nn(ZN, AND, $1, $3); } + | Expr AND expr { $$ = nn(ZN, AND, $1, $3); } + | expr AND Expr { $$ = nn(ZN, AND, $1, $3); } + | Expr OR Expr { $$ = nn(ZN, OR, $1, $3); } + | Expr OR expr { $$ = nn(ZN, OR, $1, $3); } + | expr OR Expr { $$ = nn(ZN, OR, $1, $3); } + ; + +Probe : FULL l_par varref r_par { $$ = nn($3, FULL, $3, ZN); } + | NFULL l_par varref r_par { $$ = nn($3, NFULL, $3, ZN); } + | EMPTY l_par varref r_par { $$ = nn($3, EMPTY, $3, ZN); } + | NEMPTY l_par varref r_par { $$ = nn($3,NEMPTY, $3, ZN); } ; Opt_enabler: /* none */ { $$ = ZN; } - | PROVIDED '(' full_expr ')' { if (!proper_enabler($3)) + | PROVIDED l_par full_expr r_par { if (!proper_enabler($3)) { non_fatal("invalid PROVIDED clause", (char *)0); $$ = ZN; @@ -615,23 +898,6 @@ Opt_enabler: /* none */ { $$ = ZN; } } ; - /* an Expr cannot be negated - to protect Probe expressions */ -Expr : Probe { $$ = $1; } - | '(' Expr ')' { $$ = $2; } - | Expr AND Expr { $$ = nn(ZN, AND, $1, $3); } - | Expr AND expr { $$ = nn(ZN, AND, $1, $3); } - | Expr OR Expr { $$ = nn(ZN, OR, $1, $3); } - | Expr OR expr { $$ = nn(ZN, OR, $1, $3); } - | expr AND Expr { $$ = nn(ZN, AND, $1, $3); } - | expr OR Expr { $$ = nn(ZN, OR, $1, $3); } - ; - -Probe : FULL '(' varref ')' { $$ = nn($3, FULL, $3, ZN); } - | NFULL '(' varref ')' { $$ = nn($3, NFULL, $3, ZN); } - | EMPTY '(' varref ')' { $$ = nn($3, EMPTY, $3, ZN); } - | NEMPTY '(' varref ')' { $$ = nn($3,NEMPTY, $3, ZN); } - ; - basetype: TYPE { $$->sym = ZS; $$->val = $1->val; if ($$->val == UNSIGNED) @@ -647,6 +913,9 @@ typ_list: basetype { $$ = nn($1, $1->val, ZN, ZN); } | basetype ',' typ_list { $$ = nn($1, $1->val, ZN, $3); } ; +two_args: expr ',' expr { $$ = nn(ZN, ',', $1, $3); } + ; + args : /* empty */ { $$ = ZN; } | arg { $$ = $1; } ; @@ -656,7 +925,7 @@ prargs : /* empty */ { $$ = ZN; } ; margs : arg { $$ = $1; } - | expr '(' arg ')' { if ($1->ntyp == ',') + | expr l_par arg r_par { if ($1->ntyp == ',') $$ = tail_add($1, $3); else $$ = nn(ZN, ',', $1, $3); @@ -676,9 +945,9 @@ arg : expr { if ($1->ntyp == ',') ; rarg : varref { $$ = $1; trackvar($1, $1); - trapwonly($1, "rarg"); } - | EVAL '(' expr ')' { $$ = nn(ZN,EVAL,$3,ZN); - trapwonly($1, "eval rarg"); } + trapwonly($1 /*, "rarg" */); } + | EVAL l_par expr r_par { $$ = nn(ZN,EVAL,$3,ZN); + trapwonly($1 /*, "eval rarg" */); } | CONST { $$ = nn(ZN,CONST,ZN,ZN); $$->ismtyp = $1->ismtyp; $$->val = $1->val; @@ -698,12 +967,12 @@ rargs : rarg { if ($1->ntyp == ',') else $$ = nn(ZN, ',', $1, $3); } - | rarg '(' rargs ')' { if ($1->ntyp == ',') + | rarg l_par rargs r_par { if ($1->ntyp == ',') $$ = tail_add($1, $3); else $$ = nn(ZN, ',', $1, $3); } - | '(' rargs ')' { $$ = $2; } + | l_par rargs r_par { $$ = $2; } ; nlst : NAME { $$ = nn($1, NAME, ZN, ZN); @@ -715,6 +984,138 @@ nlst : NAME { $$ = nn($1, NAME, ZN, ZN); ; %% +#define binop(n, sop) fprintf(fd, "("); recursive(fd, n->lft); \ + fprintf(fd, ") %s (", sop); recursive(fd, n->rgt); \ + fprintf(fd, ")"); +#define unop(n, sop) fprintf(fd, "%s (", sop); recursive(fd, n->lft); \ + fprintf(fd, ")"); + +static void +recursive(FILE *fd, Lextok *n) +{ + if (n) + switch (n->ntyp) { + case NEXT: + unop(n, "X"); + break; + case ALWAYS: + unop(n, "[]"); + break; + case EVENTUALLY: + unop(n, "<>"); + break; + case '!': + unop(n, "!"); + break; + case UNTIL: + binop(n, "U"); + break; + case WEAK_UNTIL: + binop(n, "W"); + break; + case RELEASE: /* see http://en.wikipedia.org/wiki/Linear_temporal_logic */ + binop(n, "V"); + break; + case OR: + binop(n, "||"); + break; + case AND: + binop(n, "&&"); + break; + case IMPLIES: + binop(n, "->"); + break; + case EQUIV: + binop(n, "<->"); + break; + case C_EXPR: + fprintf(fd, "c_expr { %s }", put_inline(fd, n->sym->name)); + break; + default: + comment(fd, n, 0); + break; + } +} + +static Lextok * +ltl_to_string(Lextok *n) +{ Lextok *m = nn(ZN, 0, ZN, ZN); + char *retval; + char ltl_formula[2048]; + FILE *tf = fopen(TMP_FILE1, "w+"); /* tmpfile() fails on Windows 7 */ + + /* convert the parsed ltl to a string + by writing into a file, using existing functions, + and then passing it to the existing interface for + conversion into a never claim + (this means parsing everything twice, which is + a little redundant, but adds only miniscule overhead) + */ + + if (!tf) + { fatal("cannot create temporary file", (char *) 0); + } + dont_simplify = 1; + recursive(tf, n); + dont_simplify = 0; + (void) fseek(tf, 0L, SEEK_SET); + + memset(ltl_formula, 0, sizeof(ltl_formula)); + retval = fgets(ltl_formula, sizeof(ltl_formula), tf); + fclose(tf); + + (void) unlink(TMP_FILE1); + + if (!retval) + { printf("%p\n", retval); + fatal("could not translate ltl ltl_formula", 0); + } + + if (1) printf("ltl %s: %s\n", ltl_name, ltl_formula); + + m->sym = lookup(ltl_formula); + + return m; +} + +int +is_temporal(int t) +{ + return (t == EVENTUALLY || t == ALWAYS || t == UNTIL + || t == WEAK_UNTIL || t == RELEASE); +} + +int +is_boolean(int t) +{ + return (t == AND || t == OR || t == IMPLIES || t == EQUIV); +} + +#if 0 +/* flags correct formula like: ltl { true U (true U true) } */ +void +sanity_check(Lextok *t) /* check proper embedding of ltl_expr */ +{ + if (!t) return; + sanity_check(t->lft); + sanity_check(t->rgt); + + if (t->lft && t->rgt) + { if (!is_boolean(t->ntyp) + && (is_temporal(t->lft->ntyp) + || is_temporal(t->rgt->ntyp))) + { printf("spin: attempt to apply '"); + explain(t->ntyp); + printf("' to '"); + explain(t->lft->ntyp); + printf("' and '"); + explain(t->rgt->ntyp); + printf("'\n"); + /* non_fatal("missing parentheses?", (char *)0); */ + } } +} +#endif + void yyerror(char *fmt, ...) { diff --git a/sys/src/cmd/spin/spinlex.c b/sys/src/cmd/spin/spinlex.c index 48c431f72..3db31cadd 100644 --- a/sys/src/cmd/spin/spinlex.c +++ b/sys/src/cmd/spin/spinlex.c @@ -1,15 +1,15 @@ /***** spin: spinlex.c *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #include +#include +#include +#include #include "spin.h" #include "y.tab.h" @@ -21,8 +21,11 @@ typedef struct IType { Symbol *nm; /* name of the type */ Lextok *cn; /* contents */ Lextok *params; /* formal pars if any */ + Lextok *rval; /* variable to assign return value, if any */ char **anms; /* literal text for actual pars */ char *prec; /* precondition for c_code or c_expr */ + int uiid; /* unique inline id */ + int is_expr; /* c_expr in an ltl formula */ int dln, cln; /* def and call linenr */ Symbol *dfn, *cfn; /* def and call filename */ struct IType *nxt; /* linked list */ @@ -32,19 +35,24 @@ typedef struct C_Added { Symbol *s; Symbol *t; Symbol *ival; + Symbol *fnm; + int lno; struct C_Added *nxt; } C_Added; extern RunList *X; extern ProcList *rdy; -extern Symbol *Fname; +extern Symbol *Fname, *oFname; extern Symbol *context, *owner; extern YYSTYPE yylval; -extern short has_last, has_code; -extern int verbose, IArgs, hastrack, separate; +extern short has_last, has_code, has_priority; +extern int verbose, IArgs, hastrack, separate, in_for; +extern int implied_semis, ltl_mode, in_seq, par_cnt; short has_stack = 0; int lineno = 1; +int scope_seq[128], scope_level = 0; +char CurScope[MAXSCOPESZ]; char yytext[2048]; FILE *yyin, *yyout; @@ -55,45 +63,62 @@ 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 -#define Token(y) { if (in_comment) goto again; \ - yylval = nn(ZN,0,ZN,ZN); return y; } +static int last_token = 0; #define ValToken(x, y) { if (in_comment) goto again; \ - yylval = nn(ZN,0,ZN,ZN); yylval->val = x; return y; } + yylval = nn(ZN,0,ZN,ZN); \ + yylval->val = x; \ + last_token = y; \ + return y; \ + } #define SymToken(x, y) { if (in_comment) goto again; \ - yylval = nn(ZN,0,ZN,ZN); yylval->sym = x; return y; } -#else -#define Token(y) { yylval = nn(ZN,0,ZN,ZN); \ - if (!in_comment) return y; else goto again; } + yylval = nn(ZN,0,ZN,ZN); \ + yylval->sym = x; \ + last_token = y; \ + return y; \ + } -#define ValToken(x, y) { yylval = nn(ZN,0,ZN,ZN); yylval->val = x; \ - if (!in_comment) return y; else goto again; } +static int getinline(void); +static void uninline(void); -#define SymToken(x, y) { yylval = nn(ZN,0,ZN,ZN); yylval->sym = x; \ - if (!in_comment) return y; else goto again; } -#endif +static int PushBack; +static int PushedBack; +static char pushedback[4096]; -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(); } - -#else +static void +push_back(char *s) +{ + if (PushedBack + strlen(s) > 4094) + { fatal("select statement too large", 0); + } + strcat(pushedback, s); + PushedBack += strlen(s); +} static int Getchar(void) { int c; + + if (PushedBack > 0 && PushBack < PushedBack) + { c = pushedback[PushBack++]; + if (PushBack == PushedBack) + { pushedback[0] = '\0'; + PushBack = PushedBack = 0; + } + return c; /* expanded select statement */ + } if (Inlining<0) - c = getc(yyin); - else - c = getinline(); -#if 1 - printf("<%c>", c); + { c = getc(yyin); + } else + { c = getinline(); + } +#if 0 + if (0) + { printf("<%c:%d>[%d] ", c, c, Inlining); + } else + { printf("%c", c); + } #endif return c; } @@ -101,15 +126,25 @@ Getchar(void) static void Ungetch(int c) { + if (PushedBack > 0 && PushBack > 0) + { PushBack--; + return; + } + if (Inlining<0) - ungetc(c,yyin); - else - uninline(); -#if 1 - printf(""); -#endif + { ungetc(c,yyin); + } else + { uninline(); + } + if (0) + { printf("\n\n", c); + } +} + +static int +notdollar(int c) +{ return (c != '$' && c != '\n'); } -#endif static int notquote(int c) @@ -133,15 +168,17 @@ isdigit_(int c) static void getword(int first, int (*tst)(int)) -{ int i=0; char c; +{ int i=0, c; yytext[i++]= (char) first; while (tst(c = Getchar())) - { yytext[i++] = c; + { yytext[i++] = (char) c; if (c == '\\') - yytext[i++] = Getchar(); /* no tst */ - } + { c = Getchar(); + yytext[i++] = (char) c; /* no tst */ + } } yytext[i] = '\0'; + Ungetch(c); } @@ -150,7 +187,8 @@ follow(int tok, int ifyes, int ifno) { int c; if ((c = Getchar()) == tok) - return ifyes; + { return ifyes; + } Ungetch(c); return ifno; @@ -161,10 +199,11 @@ static IType *seqnames; static void def_inline(Symbol *s, int ln, char *ptr, char *prc, Lextok *nms) { IType *tmp; - char *nw = (char *) emalloc((int) strlen(ptr)+1); + int cnt = 0; + char *nw = (char *) emalloc(strlen(ptr)+1); strcpy(nw, ptr); - for (tmp = seqnames; tmp; tmp = tmp->nxt) + for (tmp = seqnames; tmp; cnt++, tmp = tmp->nxt) if (!strcmp(s->name, tmp->nm->name)) { non_fatal("procedure name %s redefined", tmp->nm->name); @@ -179,11 +218,12 @@ def_inline(Symbol *s, int ln, char *ptr, char *prc, Lextok *nms) tmp->cn = (Lextok *) nw; tmp->params = nms; if (strlen(prc) > 0) - { tmp->prec = (char *) emalloc((int) strlen(prc)+1); + { tmp->prec = (char *) emalloc(strlen(prc)+1); strcpy(tmp->prec, prc); } tmp->dln = ln; tmp->dfn = Fname; + tmp->uiid = cnt+1; /* so that 0 means: not an inline */ tmp->nxt = seqnames; seqnames = tmp; } @@ -250,6 +290,20 @@ iseqname(char *t) return 0; } +Lextok * +return_statement(Lextok *n) +{ + if (Inline_stub[Inlining]->rval) + { Lextok *g = nn(ZN, NAME, ZN, ZN); + Lextok *h = Inline_stub[Inlining]->rval; + g->sym = lookup("rv_"); + return nn(h, ASGN, h, n); + } else + { fatal("return statement outside inline", (char *) 0); + } + return ZN; +} + static int getinline(void) { int c; @@ -261,16 +315,20 @@ getinline(void) c = *Inliner[Inlining]++; } } else + { c = *Inliner[Inlining]++; + } if (c == '\0') - { lineno = Inline_stub[Inlining]->cln; + { + lineno = Inline_stub[Inlining]->cln; Fname = Inline_stub[Inlining]->cfn; Inlining--; + #if 0 if (verbose&32) - printf("spin: line %d, done inlining %s\n", - lineno, Inline_stub[Inlining+1]->nm->name); + printf("spin: %s:%d, done inlining %s\n", + Fname, lineno, Inline_stub[Inlining+1]->nm->name); #endif return Getchar(); } @@ -286,6 +344,16 @@ uninline(void) Inliner[Inlining]--; } +int +is_inline(void) +{ + if (Inlining < 0) + return 0; /* i.e., not an inline */ + if (Inline_stub[Inlining] == NULL) + fatal("unexpected, inline_stub not set", 0); + return Inline_stub[Inlining]->uiid; +} + IType * find_inline(char *s) { IType *tmp; @@ -295,6 +363,7 @@ find_inline(char *s) break; if (!tmp) fatal("cannot happen, missing inline def %s", s); + return tmp; } @@ -306,7 +375,17 @@ c_state(Symbol *s, Symbol *t, Symbol *ival) /* name, scope, ival */ r->s = s; /* pointer to a data object */ r->t = t; /* size of object, or "global", or "local proctype_name" */ r->ival = ival; + r->lno = lineno; + r->fnm = Fname; r->nxt = c_added; + + if(strncmp(r->s->name, "\"unsigned unsigned", 18) == 0) + { int i; + for (i = 10; i < 18; i++) + { r->s->name[i] = ' '; + } + /* printf("corrected <%s>\n", r->s->name); */ + } c_added = r; } @@ -319,6 +398,8 @@ c_track(Symbol *s, Symbol *t, Symbol *stackonly) /* name, size */ r->t = t; r->ival = stackonly; /* abuse of name */ r->nxt = c_tracked; + r->fnm = Fname; + r->lno = lineno; c_tracked = r; if (stackonly != ZS) @@ -329,36 +410,76 @@ c_track(Symbol *s, Symbol *t, Symbol *stackonly) /* name, size */ && strcmp(stackonly->name, "\"StackOnly\"") != 0) non_fatal("expecting '[Un]Matched', saw %s", stackonly->name); else - has_stack = 1; + has_stack = 1; /* unmatched stack */ } } char * -jump_etc(char *op) -{ char *p = op; +skip_white(char *p) +{ + if (p != NULL) + { while (*p == ' ' || *p == '\t') + p++; + } else + { fatal("bad format - 1", (char *) 0); + } + return p; +} - /* kludgy - try to get the type separated from the name */ +char * +skip_nonwhite(char *p) +{ + if (p != NULL) + { while (*p != ' ' && *p != '\t') + p++; + } else + { fatal("bad format - 2", (char *) 0); + } + return p; +} - 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 */ +static char * +jump_etc(C_Added *r) +{ char *op = r->s->name; + char *p = op; + char *q = (char *) 0; + int oln = lineno; + Symbol *ofnm = Fname; + + /* try to get the type separated from the name */ + lineno = r->lno; + Fname = r->fnm; + + p = skip_white(p); /* initial white space */ + + if (strncmp(p, "enum", strlen("enum")) == 0) /* special case: a two-part typename */ + { p += strlen("enum")+1; + p = skip_white(p); + } + if (strncmp(p, "unsigned", strlen("unsigned")) == 0) /* possibly a two-part typename */ + { p += strlen("unsigned")+1; + q = p = skip_white(p); + } + p = skip_nonwhite(p); /* type name */ + p = skip_white(p); /* white space */ + while (*p == '*') p++; /* decorations */ + p = skip_white(p); /* white space */ if (*p == '\0') - fatal("c_state format (%s)", op); + { if (q) + { p = q; /* unsigned with implied 'int' */ + } else + { fatal("c_state format (%s)", op); + } } - if (strchr(p, '[') - && !strchr(p, '{')) + if (strchr(p, '[') && !strchr(p, '{')) { non_fatal("array initialization error, c_state (%s)", p); - return (char *) 0; + p = (char *) 0; } + lineno = oln; + Fname = ofnm; + return p; } @@ -379,7 +500,7 @@ c_add_globinit(FILE *fd) if (*q == '\\') *q++ = ' '; /* skip over the next */ } - p = jump_etc(r->s->name); /* e.g., "int **q" */ + p = jump_etc(r); /* e.g., "int **q" */ if (p) fprintf(fd, " now.%s = %s;\n", p, r->ival->name); @@ -391,7 +512,7 @@ c_add_globinit(FILE *fd) if (*q == '\\') *q++ = ' '; /* skip over the next */ } - p = jump_etc(r->s->name); /* e.g., "int **q" */ + p = jump_etc(r); /* e.g., "int **q" */ if (p) fprintf(fd, " %s = %s;\n", p, r->ival->name); /* no now. prefix */ @@ -413,7 +534,7 @@ c_add_locinit(FILE *fd, int tpnr, char *pnm) if (*q == '\"') *q = ' '; - p = jump_etc(r->s->name); /* e.g., "int **q" */ + p = jump_etc(r); /* e.g., "int **q" */ q = r->t->name + strlen(" Local"); while (*q == ' ' || *q == '\t') @@ -435,9 +556,9 @@ c_add_locinit(FILE *fd, int tpnr, char *pnm) } if (p) - fprintf(fd, " ((P%d *)this)->%s = %s;\n", - tpnr, p, r->ival->name); - + { fprintf(fd, "\t\t((P%d *)this)->%s = %s;\n", + tpnr, p, r->ival->name); + } } fprintf(fd, "}\n"); } @@ -513,33 +634,39 @@ c_add_sv(FILE *fd) /* 1+2 -- called in pangen1.c */ return 1; } +void +c_stack_size(FILE *fd) +{ C_Added *r; + int cnt = 0; + + for (r = c_tracked; r; r = r->nxt) + if (r->ival != ZS) + { fprintf(fd, "%s%s", + (cnt==0)?"":"+", r->t->name); + cnt++; + } + if (cnt == 0) + { fprintf(fd, "WS"); + } +} + void c_add_stack(FILE *fd) { C_Added *r; int cnt = 0; - if ((!c_added && !c_tracked) || !has_stack) return; - + if ((!c_added && !c_tracked) || !has_stack) + { return; + } for (r = c_tracked; r; r = r->nxt) if (r->ival != ZS) - cnt++; + { 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, " uchar c_stack[StackSize];\n"); } - - if (cnt == 0) fprintf(fd, "WS"); /* can't happen */ - fprintf(fd, "];\n"); } void @@ -568,6 +695,7 @@ c_add_loc(FILE *fd, char *s) /* state vector entries for proctype s */ 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"); +fprintf(fd, "/* XXX p=<%s>, s=<%s>, buf=<%s> r->s->name=<%s>XXX */\n", p, s, buf, r->s->name); while (*p == ' ' || *p == '\t') p++; if (strcmp(p, buf) == 0) @@ -578,7 +706,7 @@ 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"); + fprintf(fd, "#if defined(C_States) && (HAS_TRACK==1)\n"); for (r = c_added; r; r = r->nxt) { r->s->name[strlen(r->s->name)-1] = ' '; r->s->name[0] = ' '; /* remove the "s */ @@ -610,9 +738,10 @@ c_add_def(FILE *fd) /* 3 - called in plunk_c_fcts() */ } if (has_stack) - { fprintf(fd, "void\nc_stack(uchar *p_t_r)\n{\n"); + { fprintf(fd, "int cpu_printf(const char *, ...);\n"); + fprintf(fd, "void\nc_stack(uchar *p_t_r)\n{\n"); fprintf(fd, "#ifdef VERBOSE\n"); - fprintf(fd, " printf(\"c_stack %%u\\n\", p_t_r);\n"); + fprintf(fd, " cpu_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; @@ -630,7 +759,7 @@ c_add_def(FILE *fd) /* 3 - called in plunk_c_fcts() */ fprintf(fd, "void\nc_update(uchar *p_t_r)\n{\n"); fprintf(fd, "#ifdef VERBOSE\n"); - fprintf(fd, " printf(\"c_update %%u\\n\", p_t_r);\n"); + fprintf(fd, " printf(\"c_update %%p\\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 @@ -660,7 +789,7 @@ c_add_def(FILE *fd) /* 3 - called in plunk_c_fcts() */ if (has_stack) { fprintf(fd, "void\nc_unstack(uchar *p_t_r)\n{\n"); fprintf(fd, "#ifdef VERBOSE\n"); - fprintf(fd, " printf(\"c_unstack %%u\\n\", p_t_r);\n"); + fprintf(fd, " cpu_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; @@ -675,7 +804,7 @@ c_add_def(FILE *fd) /* 3 - called in plunk_c_fcts() */ fprintf(fd, "void\nc_revert(uchar *p_t_r)\n{\n"); fprintf(fd, "#ifdef VERBOSE\n"); - fprintf(fd, " printf(\"c_revert %%u\\n\", p_t_r);\n"); + fprintf(fd, " printf(\"c_revert %%p\\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 @@ -708,11 +837,13 @@ plunk_reverse(FILE *fd, IType *p, int matchthis) plunk_reverse(fd, p->nxt, matchthis); if (!p->nm->context - && p->nm->type == matchthis) + && p->nm->type == matchthis + && p->is_expr == 0) { fprintf(fd, "\n/* start of %s */\n", p->nm->name); z = (char *) p->cn; while (*z == '\n' || *z == '\r' || *z == '\\') - z++; + { z++; + } /* e.g.: \#include "..." */ y = z; @@ -772,14 +903,28 @@ check_inline(IType *tmp) } } } +extern short terse; +extern short nocast; + void plunk_expr(FILE *fd, char *s) { IType *tmp; + char *q; tmp = find_inline(s); check_inline(tmp); - fprintf(fd, "%s", (char *) tmp->cn); + if (terse && nocast) + { for (q = (char *) tmp->cn; q && *q != '\0'; q++) + { fflush(fd); + if (*q == '"') + { fprintf(fd, "\\"); + } + fprintf(fd, "%c", *q); + } + } else + { fprintf(fd, "%s", (char *) tmp->cn); + } } void @@ -791,9 +936,11 @@ preruse(FILE *fd, Lextok *n) /* check a condition for c_expr with preconditions { 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, "trpt++; trpt->pr = II; trpt->o_t = t; trpt->st = tt; "); + fprintf(fd, "uerror(\"c_expr line %d precondition false: %s\"); continue;", + tmp->dln, tmp->prec); + fprintf(fd, " } else { printf(\"pan: precondition false: %s\\n\"); ", + tmp->prec); fprintf(fd, "_m = 3; goto P999; } } \n\t\t"); } } else @@ -813,8 +960,25 @@ glob_inline(char *s) || strchr(bdy, '(') > bdy); /* possible C-function call */ } +char * +put_inline(FILE *fd, char *s) +{ IType *tmp; + + tmp = find_inline(s); + check_inline(tmp); + return (char *) tmp->cn; +} + void -plunk_inline(FILE *fd, char *s, int how) /* c_code with precondition */ +mark_last(void) +{ + if (seqnames) + { seqnames->is_expr = 1; + } +} + +void +plunk_inline(FILE *fd, char *s, int how, int gencode) /* c_code with precondition */ { IType *tmp; tmp = find_inline(s); @@ -822,16 +986,32 @@ plunk_inline(FILE *fd, char *s, int how) /* c_code with precondition */ 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, "if (!(%s)) { if (!readtrail) {", + tmp->prec); + fprintf(fd, " uerror(\"c_code line %d precondition false: %s\"); continue; ", + tmp->dln, + tmp->prec); + fprintf(fd, "} else { "); + fprintf(fd, "printf(\"pan: precondition false: %s\\n\"); _m = 3; goto P999; } } ", + tmp->prec); } + + if (!gencode) /* not in d_step */ + { fprintf(fd, "\n\t\tsv_save();"); + } + fprintf(fd, "%s", (char *) tmp->cn); fprintf(fd, " }\n"); } +int +side_scan(char *t, char *pat) +{ char *r = strstr(t, pat); + return (r + && *(r-1) != '"' + && *(r-1) != '\''); +} + void no_side_effects(char *s) { IType *tmp; @@ -845,9 +1025,9 @@ no_side_effects(char *s) tmp = find_inline(s); t = (char *) tmp->cn; - if (strchr(t, ';') - || strstr(t, "++") - || strstr(t, "--")) + if (side_scan(t, ";") + || side_scan(t, "++") + || side_scan(t, "--")) { bad: lineno = tmp->dln; Fname = tmp->dfn; @@ -857,8 +1037,10 @@ bad: lineno = tmp->dln; while ((t = strchr(t, '=')) != NULL) { if (*(t-1) == '!' || *(t-1) == '>' - || *(t-1) == '<') - { t++; + || *(t-1) == '<' + || *(t-1) == '"' + || *(t-1) == '\'') + { t += 2; continue; } t++; @@ -869,16 +1051,16 @@ bad: lineno = tmp->dln; } void -pickup_inline(Symbol *t, Lextok *apars) +pickup_inline(Symbol *t, Lextok *apars, Lextok *rval) { IType *tmp; Lextok *p, *q; int j; tmp = find_inline(t->name); if (++Inlining >= MAXINL) - fatal("inline fcts too deeply nested", 0); - + fatal("inlines nested too deeply", 0); tmp->cln = lineno; /* remember calling point */ tmp->cfn = Fname; /* and filename */ + tmp->rval = rval; for (p = apars, q = tmp->params, j = 0; p && q; p = p->rgt, q = q->rgt) j++; /* count them */ @@ -887,7 +1069,7 @@ pickup_inline(Symbol *t, Lextok *apars) tmp->anms = (char **) emalloc(j * sizeof(char *)); for (p = apars, j = 0; p; p = p->rgt, j++) - { tmp->anms[j] = (char *) emalloc((int) strlen(IArg_cont[j])+1); + { tmp->anms[j] = (char *) emalloc(strlen(IArg_cont[j])+1); strcpy(tmp->anms[j], IArg_cont[j]); } @@ -897,14 +1079,18 @@ pickup_inline(Symbol *t, Lextok *apars) Inline_stub[Inlining] = tmp; #if 0 if (verbose&32) - printf("spin: line %d, file %s, inlining '%s' (from line %d, file %s)\n", - tmp->cln, tmp->cfn->name, t->name, tmp->dln, tmp->dfn->name); + printf("spin: %s:%d, inlining '%s' (from %s:%d)\n", + tmp->cfn->name, tmp->cln, t->name, tmp->dfn->name, tmp->dln); #endif for (j = 0; j < Inlining; j++) - if (Inline_stub[j] == Inline_stub[Inlining]) - fatal("cyclic inline attempt on: %s", t->name); + { if (Inline_stub[j] == Inline_stub[Inlining]) + { fatal("cyclic inline attempt on: %s", t->name); + } } + last_token = SEMI; /* avoid insertion of extra semi */ } +extern int pp_mode; + static void do_directive(int first) { int c = first; /* handles lines starting with pound */ @@ -930,13 +1116,15 @@ do_directive(int first) fatal("malformed preprocessor directive - .fname", 0); if ((c = Getchar()) != '\"') - fatal("malformed preprocessor directive - .fname", 0); + { printf("got %c, expected \" -- lineno %d\n", c, lineno); + fatal("malformed preprocessor directive - .fname (%s)", yytext); + } - getword(c, notquote); + getword(Getchar(), notquote); /* was getword(c, notquote); */ if (Getchar() != '\"') fatal("malformed preprocessor directive - fname.", 0); - strcat(yytext, "\""); + /* strcat(yytext, "\""); */ Fname = lookup(yytext); done: while (Getchar() != '\n') @@ -965,41 +1153,44 @@ precondition(char *q) break; } } - fatal("cannot happen", (char *) 0); + fatal("cannot happen", (char *) 0); /* unreachable */ } + Symbol * prep_inline(Symbol *s, Lextok *nms) { int c, nest = 1, dln, firstchar, cnr; - char *p, buf[SOMETHINGBIG], buf2[RATHERSMALL]; + char *p; Lextok *t; + static char Buf1[SOMETHINGBIG], Buf2[RATHERSMALL]; static int c_code = 1; for (t = nms; t; t = t->rgt) if (t->lft) { if (t->lft->ntyp != NAME) - fatal("bad param to inline %s", s->name); + fatal("bad param to inline %s", s?s->name:"--"); t->lft->sym->hidden |= 32; } if (!s) /* C_Code fragment */ { s = (Symbol *) emalloc(sizeof(Symbol)); - s->name = (char *) emalloc((int) strlen("c_code")+26); + s->name = (char *) emalloc(strlen("c_code")+26); sprintf(s->name, "c_code%d", c_code++); s->context = context; s->type = CODE_FRAG; } else - s->type = PREDEF; + { s->type = PREDEF; + } - p = &buf[0]; - buf2[0] = '\0'; + p = &Buf1[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; } */ + precondition(&Buf2[0]); /* e.g., c_code [p] { r = p-r; } */ continue; case '{': break; @@ -1017,19 +1208,22 @@ bad: fatal("bad inline: %s", s->name); dln = lineno; if (s->type == CODE_FRAG) { if (verbose&32) - sprintf(buf, "\t/* line %d %s */\n\t\t", + { sprintf(Buf1, "\t/* line %d %s */\n\t\t", lineno, Fname->name); - else - strcpy(buf, ""); + } else + { strcpy(Buf1, ""); + } } else - sprintf(buf, "\n#line %d %s\n{", lineno, Fname->name); - p += strlen(buf); + { sprintf(Buf1, "\n#line %d \"%s\"\n{", lineno, Fname->name); + } + p += strlen(Buf1); firstchar = 1; cnr = 1; /* not zero */ more: - *p++ = c = Getchar(); - if (p - buf >= SOMETHINGBIG) + c = Getchar(); + *p++ = (char) c; + if (p - Buf1 >= SOMETHINGBIG) fatal("inline text too long", 0); switch (c) { case '\n': @@ -1045,11 +1239,13 @@ more: if (--nest <= 0) { *p = '\0'; 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", + { *--p = '\0'; /* remove trailing '}' */ + } + def_inline(s, dln, &Buf1[0], &Buf2[0], nms); + if (firstchar) + { printf("%3d: %s, warning: empty inline definition (%s)\n", dln, Fname->name, s->name); + } return s; /* normal return */ } break; @@ -1057,30 +1253,240 @@ more: if (cnr == 0) { p--; do_directive(c); /* reads to newline */ - break; - } /* else fall through */ - default: - firstchar = 0; + } else + { firstchar = 0; + cnr++; + } + break; case '\t': case ' ': case '\f': cnr++; break; + case '"': + do { + c = Getchar(); + *p++ = (char) c; + if (c == '\\') + { *p++ = (char) Getchar(); + } + if (p - Buf1 >= SOMETHINGBIG) + { fatal("inline text too long", 0); + } + } while (c != '"'); /* end of string */ + /* *p = '\0'; */ + break; + case '\'': + c = Getchar(); + *p++ = (char) c; + if (c == '\\') + { *p++ = (char) Getchar(); + } + c = Getchar(); + *p++ = (char) c; + assert(c == '\''); + break; + default: + firstchar = 0; + cnr++; + break; } goto more; } +static void +set_cur_scope(void) +{ int i; + char tmpbuf[256]; + + strcpy(CurScope, "_"); + + if (context) + for (i = 0; i < scope_level; i++) + { sprintf(tmpbuf, "%d_", scope_seq[i]); + strcat(CurScope, tmpbuf); + } +} + static int +pre_proc(void) +{ char b[512]; + int c, i = 0; + + b[i++] = '#'; + while ((c = Getchar()) != '\n' && c != EOF) + { b[i++] = (char) c; + } + b[i] = '\0'; + yylval = nn(ZN, 0, ZN, ZN); + yylval->sym = lookup(b); + return PREPROC; +} + +static int specials[] = { + '}', ')', ']', + OD, FI, ELSE, BREAK, + C_CODE, C_EXPR, C_DECL, + NAME, CONST, INCR, DECR, 0 +}; + +int +follows_token(int c) +{ int i; + + for (i = 0; specials[i]; i++) + { if (c == specials[i]) + { return 1; + } } + return 0; +} +#define DEFER_LTL +#ifdef DEFER_LTL +/* defer ltl formula to the end of the spec + * no matter where they appear in the original + */ + +static int deferred = 0; +static FILE *defer_fd; + +int +get_deferred(void) +{ + if (!defer_fd) + { return 0; /* nothing was deferred */ + } + fclose(defer_fd); + + defer_fd = fopen(TMP_FILE2, "r"); + if (!defer_fd) + { non_fatal("cannot retrieve deferred ltl formula", (char *) 0); + return 0; + } + fclose(yyin); + yyin = defer_fd; + return 1; +} + +void +zap_deferred(void) +{ + (void) unlink(TMP_FILE2); +} + +int +put_deferred(void) +{ int c, cnt; + if (!defer_fd) + { defer_fd = fopen(TMP_FILE2, "w+"); + if (!defer_fd) + { non_fatal("cannot defer ltl expansion", (char *) 0); + return 0; + } } + fprintf(defer_fd, "ltl "); + cnt = 0; + while ((c = getc(yyin)) != EOF) + { if (c == '{') + { cnt++; + } + if (c == '}') + { cnt--; + if (cnt == 0) + { break; + } } + fprintf(defer_fd, "%c", c); + } + fprintf(defer_fd, "}\n"); + fflush(defer_fd); + return 1; +} +#endif + +#define EXPAND_SELECT +#ifdef EXPAND_SELECT +static char tmp_hold[256]; +static int tmp_has; + +void +new_select(void) +{ tmp_hold[0] = '\0'; + tmp_has = 0; +} + +int +scan_to(int stop, int (*tst)(int), char *buf) +{ int c, i = 0; + + do { c = Getchar(); + if (tmp_has < sizeof(tmp_hold)) + { tmp_hold[tmp_has++] = c; + } + if (c == '\n') + { lineno++; + } else if (buf) + { buf[i++] = c; + } + if (tst && !tst(c) && c != ' ' && c != '\t') + { break; + } + } while (c != stop && c != EOF); + + if (buf) + { buf[i-1] = '\0'; + } + + if (c != stop) + { if (0) + { printf("saw: '%c', expected '%c'\n", c, stop); + } + if (tmp_has < sizeof(tmp_hold)) + { tmp_hold[tmp_has] = '\0'; + push_back(tmp_hold); + if (0) + { printf("pushed back: <'%s'>\n", tmp_hold); + } + return 0; /* internal expansion fails */ + } else + { fatal("expecting select ( name : constant .. constant )", 0); + } } + return 1; /* success */ +} +#endif + +int lex(void) { int c; - again: c = Getchar(); yytext[0] = (char) c; yytext[1] = '\0'; switch (c) { + case EOF: +#ifdef DEFER_LTL + if (!deferred) + { deferred = 1; + if (get_deferred()) + { goto again; + } + } else + { zap_deferred(); + } +#endif + return c; case '\n': /* newline */ lineno++; + /* make most semi-colons optional */ + if (implied_semis + /* && context */ + && in_seq + && par_cnt == 0 + && follows_token(last_token)) + { if (0) + { printf("insert ; line %d, last_token %d in_seq %d\n", + lineno-1, last_token, in_seq); + } + ValToken(1, SEMI); + } + /* else fall thru */ case '\r': /* carriage return */ goto again; @@ -1089,6 +1495,10 @@ again: case '#': /* preprocessor directive */ if (in_comment) goto again; + if (pp_mode) + { last_token = PREPROC; + return pre_proc(); + } do_directive(c); goto again; @@ -1099,6 +1509,13 @@ again: strcat(yytext, "\""); SymToken(lookup(yytext), STRING) + case '$': + getword('\"', notdollar); + if (Getchar() != '$') + fatal("ltl definition not terminated", yytext); + strcat(yytext, "\""); + SymToken(lookup(yytext), STRING) + case '\'': /* new 3.0.9 */ c = Getchar(); if (c == '\\') @@ -1117,20 +1534,104 @@ again: } if (isdigit_(c)) - { getword(c, isdigit_); - ValToken(atoi(yytext), CONST) + { long int nr; + getword(c, isdigit_); + errno = 0; + nr = strtol(yytext, NULL, 10); + if (errno != 0) + { fprintf(stderr, "spin: value out of range: '%s' read as '%d'\n", + yytext, (int) nr); + } + ValToken((int)nr, CONST) } if (isalpha_(c) || c == '_') { getword(c, isalnum_); if (!in_comment) { c = check_name(yytext); - if (c) return c; + +#ifdef EXPAND_SELECT + if (c == SELECT && Inlining < 0) + { char name[64], from[32], upto[32]; + int i, a, b; + new_select(); + if (!scan_to('(', 0, 0) + || !scan_to(':', isalnum, name) + || !scan_to('.', isdigit, from) + || !scan_to('.', 0, 0) + || !scan_to(')', isdigit, upto)) + { goto not_expanded; + } + a = atoi(from); + b = atoi(upto); + if (0) + { printf("Select %s from %d to %d\n", + name, a, b); + } + if (a > b) + { non_fatal("bad range in select statement", 0); + goto again; + } + if (b - a <= 32) + { push_back("if "); + for (i = a; i <= b; i++) + { char buf[128]; + push_back(":: "); + sprintf(buf, "%s = %d ", + name, i); + push_back(buf); + } + push_back("fi "); + } else + { char buf[128]; + sprintf(buf, "%s = %d; do ", + name, a); + push_back(buf); + sprintf(buf, ":: (%s < %d) -> %s++ ", + name, b, name); + push_back(buf); + push_back(":: break od; "); + } + goto again; + } +not_expanded: +#endif + +#ifdef DEFER_LTL + if (c == LTL && !deferred) + { if (put_deferred()) + { goto again; + } } +#endif + if (c) + { last_token = c; + return c; + } /* else fall through */ } goto again; } + if (ltl_mode) + { switch (c) { + case '-': c = follow('>', IMPLIES, '-'); break; + case '[': c = follow(']', ALWAYS, '['); break; + case '<': c = follow('>', EVENTUALLY, '<'); + if (c == '<') + { c = Getchar(); + if (c == '-') + { c = follow('>', EQUIV, '-'); + if (c == '-') + { Ungetch(c); + c = '<'; + } + } else + { Ungetch(c); + c = '<'; + } } + default: break; + } } + switch (c) { case '/': c = follow('*', 0, '/'); if (!c) { in_comment = 1; goto again; } @@ -1139,7 +1640,7 @@ again: if (!c) { in_comment = 0; goto again; } break; case ':': c = follow(':', SEP, ':'); break; - case '-': c = follow('>', SEMI, follow('-', DECR, '-')); break; + case '-': c = follow('>', ARROW, follow('-', DECR, '-')); break; case '+': c = follow('+', INCR, '+'); break; case '<': c = follow('<', LSHIFT, follow('=', LE, LT)); break; case '>': c = follow('>', RSHIFT, follow('=', GE, GT)); break; @@ -1149,11 +1650,34 @@ again: case '&': c = follow('&', AND, '&'); break; case '|': c = follow('|', OR, '|'); break; case ';': c = SEMI; break; + case '.': c = follow('.', DOTDOT, '.'); break; + case '{': scope_seq[scope_level++]++; set_cur_scope(); break; + case '}': scope_level--; set_cur_scope(); break; default : break; } - Token(c) + ValToken(0, c) } +static struct { + char *s; int tok; +} LTL_syms[] = { + /* [], <>, ->, and <-> are intercepted in lex() */ + { "U", UNTIL }, + { "V", RELEASE }, + { "W", WEAK_UNTIL }, + { "X", NEXT }, + { "always", ALWAYS }, + { "eventually", EVENTUALLY }, + { "until", UNTIL }, + { "stronguntil",UNTIL }, + { "weakuntil", WEAK_UNTIL }, + { "release", RELEASE }, + { "next", NEXT }, + { "implies", IMPLIES }, + { "equivalent", EQUIV }, + { 0, 0 }, +}; + static struct { char *s; int tok; int val; char *sym; } Names[] = { @@ -1178,14 +1702,19 @@ static struct { {"eval", EVAL, 0, 0}, {"false", CONST, 0, 0}, {"fi", FI, 0, 0}, + {"for", FOR, 0, 0}, {"full", FULL, 0, 0}, + {"get_priority", GET_P, 0, 0}, {"goto", GOTO, 0, 0}, {"hidden", HIDDEN, 0, ":hide:"}, {"if", IF, 0, 0}, + {"in", IN, 0, 0}, {"init", INIT, 0, ":init:"}, + {"inline", INLINE, 0, 0}, {"int", TYPE, INT, 0}, {"len", LEN, 0, 0}, {"local", ISLOCAL, 0, ":local:"}, + {"ltl", LTL, 0, ":ltl:"}, {"mtype", TYPE, MTYPE, 0}, {"nempty", NEMPTY, 0, 0}, {"never", CLAIM, 0, ":never:"}, @@ -1201,9 +1730,11 @@ static struct { {"priority", PRIORITY, 0, 0}, {"proctype", PROCTYPE, 0, 0}, {"provided", PROVIDED, 0, 0}, + {"return", RETURN, 0, 0}, {"run", RUN, 0, 0}, {"d_step", D_STEP, 0, 0}, - {"inline", INLINE, 0, 0}, + {"select", SELECT, 0, 0}, + {"set_priority", SET_P, 0, 0}, {"short", TYPE, SHORT, 0}, {"skip", CONST, 1, 0}, {"timeout", TIMEOUT, 0, 0}, @@ -1223,13 +1754,23 @@ check_name(char *s) { int i; yylval = nn(ZN, 0, ZN, ZN); + + if (ltl_mode) + { for (i = 0; LTL_syms[i].s; i++) + { if (strcmp(s, LTL_syms[i].s) == 0) + { return LTL_syms[i].tok; + } } } + for (i = 0; Names[i].s; i++) - if (strcmp(s, Names[i].s) == 0) + { if (strcmp(s, Names[i].s) == 0) { yylval->val = Names[i].val; if (Names[i].sym) yylval->sym = lookup(Names[i].sym); + if (Names[i].tok == IN && !in_for) + { continue; + } return Names[i].tok; - } + } } if ((yylval->val = ismtype(s)) != 0) { yylval->ismtyp = 1; @@ -1239,6 +1780,9 @@ check_name(char *s) if (strcmp(s, "_last") == 0) has_last++; + if (strcmp(s, "_priority") == 0) + has_priority++; + if (Inlining >= 0 && !ReDiRect) { Lextok *tt, *t = Inline_stub[Inlining]->params; @@ -1253,19 +1797,29 @@ check_name(char *s) Inline_stub[Inlining]->nm->name, Inline_stub[Inlining]->anms[i]); #endif - 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", + printf("spin: %s:%d replacement value: %s\n", + oFname->name?oFname->name:"--", lineno, tt->lft->sym->name); + fatal("formal par of %s contains replacement value", Inline_stub[Inlining]->nm->name); yylval->ntyp = tt->lft->ntyp; yylval->sym = lookup(tt->lft->sym->name); return NAME; } + + /* check for occurrence of param as field of struct */ + { char *ptr = Inline_stub[Inlining]->anms[i]; + while ((ptr = strstr(ptr, s)) != NULL) + { if (*(ptr-1) == '.' + || *(ptr+strlen(s)) == '.') + { fatal("formal par of %s used in structure name", + Inline_stub[Inlining]->nm->name); + } + ptr++; + } } ReDiRect = Inline_stub[Inlining]->anms[i]; return 0; } } @@ -1293,13 +1847,16 @@ yylex(void) if (hold) { c = hold; hold = 0; + last_token = c; } else { c = lex(); if (last == ELSE && c != SEMI + && c != ARROW && c != FI) { hold = c; last = 0; + last_token = SEMI; return SEMI; } if (last == '}' @@ -1312,12 +1869,14 @@ yylex(void) && c != '}' && c != UNLESS && c != SEMI + && c != ARROW && c != EOF) { hold = c; last = 0; + last_token = SEMI; return SEMI; /* insert ';' */ } - if (c == SEMI) + if (c == SEMI || c == ARROW) { /* if context, we're not in a typedef * because they're global. * if owner, we're at the end of a ref @@ -1328,6 +1887,7 @@ yylex(void) if (context) owner = ZS; hold = lex(); /* look ahead */ if (hold == '}' + || hold == ARROW || hold == SEMI) { c = hold; /* omit ';' */ hold = 0; @@ -1346,16 +1906,26 @@ yylex(void) { IArgno = 0; IArg_cont[0][0] = '\0'; } else + { assert(strlen(IArg_cont[IArgno])+strlen(yytext) < sizeof(IArg_cont)); strcat(IArg_cont[IArgno], yytext); + } } else if (strcmp(yytext, ")") == 0) { if (--IArg_nst > 0) + { assert(strlen(IArg_cont[IArgno])+strlen(yytext) < sizeof(IArg_cont)); strcat(IArg_cont[IArgno], yytext); + } } else if (c == CONST && yytext[0] == '\'') { sprintf(yytext, "'%c'", yylval->val); + assert(strlen(IArg_cont[IArgno])+strlen(yytext) < sizeof(IArg_cont)); + strcat(IArg_cont[IArgno], yytext); + } else if (c == CONST) + { sprintf(yytext, "%d", yylval->val); + assert(strlen(IArg_cont[IArgno])+strlen(yytext) < sizeof(IArg_cont)); strcat(IArg_cont[IArgno], yytext); } else { switch (c) { + case ARROW: strcpy(yytext, "->"); break; /* NEW */ case SEP: strcpy(yytext, "::"); break; case SEMI: strcpy(yytext, ";"); break; case DECR: strcpy(yytext, "--"); break; @@ -1376,9 +1946,9 @@ yylex(void) case AND: strcpy(yytext, "&&"); break; case OR: strcpy(yytext, "||"); break; } + assert(strlen(IArg_cont[IArgno])+strlen(yytext) < sizeof(IArg_cont)); strcat(IArg_cont[IArgno], yytext); } } - return c; } diff --git a/sys/src/cmd/spin/structs.c b/sys/src/cmd/spin/structs.c index 5ade6054e..d5388f778 100644 --- a/sys/src/cmd/spin/structs.c +++ b/sys/src/cmd/spin/structs.c @@ -1,13 +1,10 @@ /***** spin: structs.c *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #include "spin.h" #include "y.tab.h" @@ -19,7 +16,7 @@ typedef struct UType { } UType; extern Symbol *Fname; -extern int lineno, depth, Expand_Ok; +extern int lineno, depth, Expand_Ok, has_hidden, in_for; Symbol *owner; @@ -33,14 +30,16 @@ void setuname(Lextok *n) { UType *tmp; + if (!owner) + fatal("illegal reference inside typedef", (char *) 0); + for (tmp = Unames; tmp; tmp = tmp->nxt) if (!strcmp(owner->name, tmp->nm->name)) { non_fatal("typename %s was defined before", tmp->nm->name); return; } - if (!owner) fatal("illegal reference inside typedef", - (char *) 0); + tmp = (UType *) emalloc(sizeof(UType)); tmp->nm = owner; tmp->cn = n; @@ -102,21 +101,22 @@ setutype(Lextok *p, Symbol *t, Lextok *vis) /* user-defined types */ { lineno = n->ln; Fname = n->fn; if (n->sym->type) - non_fatal("redeclaration of '%s'", n->sym->name); + fatal("redeclaration of '%s'", n->sym->name); if (n->sym->nbits > 0) - non_fatal("(%s) only an unsigned can have width-field", - n->sym->name); + non_fatal("(%s) only an unsigned can have width-field", + n->sym->name); if (Expand_Ok) n->sym->hidden |= (4|8|16); /* formal par */ if (vis) - { if (strncmp(vis->sym->name, ":hide:", 6) == 0) - n->sym->hidden |= 1; - else if (strncmp(vis->sym->name, ":show:", 6) == 0) + { if (strncmp(vis->sym->name, ":hide:", (size_t) 6) == 0) + { n->sym->hidden |= 1; + has_hidden++; + } else if (strncmp(vis->sym->name, ":show:", (size_t) 6) == 0) n->sym->hidden |= 2; - else if (strncmp(vis->sym->name, ":local:", 7) == 0) + else if (strncmp(vis->sym->name, ":local:", (size_t) 7) == 0) n->sym->hidden |= 64; } n->sym->type = STRUCT; /* classification */ @@ -196,6 +196,7 @@ Rval_struct(Lextok *n, Symbol *v, int xinit) /* n varref, v valref */ fatal("non-zero 'rgt' on non-structure", 0); ix = eval(tmp->lft); +/* printf("%d: ix: %d (%d) %d\n", depth, ix, tl->nel, tl->val[ix]); */ if (ix >= tl->nel || ix < 0) fatal("indexing error \'%s\'", tl->name); @@ -222,10 +223,12 @@ Lval_struct(Lextok *n, Symbol *v, int xinit, int a) /* a = assigned value */ fatal("indexing error \'%s\'", tl->name); if (tl->nbits > 0) - a = (a & ((1<nbits)-1)); - tl->val[ix] = a; - tl->setat = depth; + a = (a & ((1<nbits)-1)); + if (a != tl->val[ix]) + { tl->val[ix] = a; + tl->setat = depth; + } return 1; } @@ -246,7 +249,7 @@ is_lst: for (fp = n; fp; fp = fp->rgt) for (tl = fp->lft; tl; tl = tl->rgt) { if (tl->sym->type == STRUCT) - { if (tl->sym->nel != 1) + { if (tl->sym->nel > 1 || tl->sym->isarray) fatal("array of structures in param list, %s", tl->sym->name); cnt += Cnt_flds(tl->sym->Slst); @@ -266,9 +269,9 @@ Sym_typ(Lextok *t) return s->type; if (!t->rgt - || !t->rgt->ntyp == '.' + || t->rgt->ntyp != '.' /* gh: had ! in wrong place */ || !t->rgt->lft) - return STRUCT; /* not a field reference */ + return STRUCT; /* not a field reference */ return Sym_typ(t->rgt->lft); } @@ -315,6 +318,7 @@ cpnn(Lextok *s, int L, int R, int S) if (!s) return ZN; d = (Lextok *) emalloc(sizeof(Lextok)); + d->uiid = s->uiid; d->ntyp = s->ntyp; d->val = s->val; d->ln = s->ln; @@ -353,7 +357,7 @@ full_name(FILE *fd, Lextok *n, Symbol *v, int xinit) goto out; } fprintf(fd, ".%s", tl->name); -out: if (tmp->sym->nel > 1) +out: if (tmp->sym->nel > 1 || tmp->sym->isarray == 1) { fprintf(fd, "[%d]", eval(tmp->lft)); hiddenarrays = 1; } @@ -391,7 +395,7 @@ struct_name(Lextok *n, Symbol *v, int xinit, char *buf) } sprintf(lbuf, ".%s", tl->name); strcat(buf, lbuf); - if (tmp->sym->nel > 1) + if (tmp->sym->nel > 1 || tmp->sym->isarray == 1) { sprintf(lbuf, "[%d]", eval(tmp->lft)); strcat(buf, lbuf); } @@ -405,10 +409,10 @@ walk2_struct(char *s, Symbol *z) extern void Done_case(char *, Symbol *); ini_struct(z); - if (z->nel == 1) + if (z->nel == 1 && z->isarray == 0) sprintf(eprefix, "%s%s.", s, z->name); for (ix = 0; ix < z->nel; ix++) - { if (z->nel > 1) + { if (z->nel > 1 || z->isarray == 1) sprintf(eprefix, "%s%s[%d].", s, z->name, ix); for (fp = z->Sval[ix]; fp; fp = fp->rgt) for (tl = fp->lft; tl; tl = tl->rgt) @@ -426,10 +430,10 @@ walk_struct(FILE *ofd, int dowhat, char *s, Symbol *z, char *a, char *b, char *c int ix; ini_struct(z); - if (z->nel == 1) + if (z->nel == 1 && z->isarray == 0) sprintf(eprefix, "%s%s.", s, z->name); for (ix = 0; ix < z->nel; ix++) - { if (z->nel > 1) + { if (z->nel > 1 || z->isarray == 1) sprintf(eprefix, "%s%s[%d].", s, z->name, ix); for (fp = z->Sval[ix]; fp; fp = fp->rgt) for (tl = fp->lft; tl; tl = tl->rgt) @@ -443,7 +447,7 @@ walk_struct(FILE *ofd, int dowhat, char *s, Symbol *z, char *a, char *b, char *c void c_struct(FILE *fd, char *ipref, Symbol *z) { Lextok *fp, *tl; - char pref[256], eprefix[256]; + char pref[256], eprefix[300]; int ix; ini_struct(z); @@ -452,7 +456,7 @@ c_struct(FILE *fd, char *ipref, Symbol *z) for (fp = z->Sval[ix]; fp; fp = fp->rgt) for (tl = fp->lft; tl; tl = tl->rgt) { strcpy(eprefix, ipref); - if (z->nel > 1) + if (z->nel > 1 || z->isarray == 1) { /* insert index before last '.' */ eprefix[strlen(eprefix)-1] = '\0'; sprintf(pref, "[ %d ].", ix); @@ -476,7 +480,7 @@ dump_struct(Symbol *z, char *prefix, RunList *r) ini_struct(z); for (ix = 0; ix < z->nel; ix++) - { if (z->nel > 1) + { if (z->nel > 1 || z->isarray == 1) sprintf(eprefix, "%s[%d]", prefix, ix); else strcpy(eprefix, prefix); @@ -484,7 +488,7 @@ dump_struct(Symbol *z, char *prefix, RunList *r) for (fp = z->Sval[ix]; fp; fp = fp->rgt) for (tl = fp->lft; tl; tl = tl->rgt) { if (tl->sym->type == STRUCT) - { char pref[256]; + { char pref[300]; strcpy(pref, eprefix); strcat(pref, "."); strcat(pref, tl->sym->name); @@ -498,7 +502,7 @@ dump_struct(Symbol *z, char *prefix, RunList *r) if (r) printf("%s(%d):", r->n->name, r->pid); printf("%s.%s", eprefix, tl->sym->name); - if (tl->sym->nel > 1) + if (tl->sym->nel > 1 || tl->sym->isarray == 1) printf("[%d]", jx); printf(" = "); sr_mesg(stdout, tl->sym->val[jx], @@ -579,9 +583,11 @@ mk_explicit(Lextok *n, int Ok, int Ntyp) int i, cnt; extern int IArgs; if (n->sym->type != STRUCT + || in_for || is_explicit(n)) return n; + if (n->rgt && n->rgt->ntyp == '.' && n->rgt->lft diff --git a/sys/src/cmd/spin/sym.c b/sys/src/cmd/spin/sym.c index 0001d2f5f..6985f0a82 100644 --- a/sys/src/cmd/spin/sym.c +++ b/sys/src/cmd/spin/sym.c @@ -1,25 +1,27 @@ /***** spin: sym.c *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #include "spin.h" #include "y.tab.h" extern Symbol *Fname, *owner; extern int lineno, depth, verbose, NamesNotAdded, deadvar; +extern int has_hidden, m_loss, old_scope_rules; extern short has_xu; +extern char CurScope[MAXSCOPESZ]; Symbol *context = ZS; Ordered *all_names = (Ordered *)0; int Nid = 0; +Lextok *Mtype = (Lextok *) 0; +Lextok *runstmnts = ZN; + static Ordered *last_name = (Ordered *)0; static Symbol *symtab[Nhash+1]; @@ -31,12 +33,12 @@ samename(Symbol *a, Symbol *b) return !strcmp(a->name, b->name); } -int -hash(char *s) -{ int h=0; +unsigned int +hash(const char *s) +{ unsigned int h = 0; while (*s) - { h += *s++; + { h += (unsigned int) *s++; h <<= 1; if (h&(Nhash+1)) h |= 1; @@ -44,31 +46,89 @@ hash(char *s) return h&Nhash; } +void +disambiguate(void) +{ Ordered *walk; + Symbol *sp; + char *n, *m; + + if (old_scope_rules) + return; + + /* prepend the scope_prefix to the names */ + + for (walk = all_names; walk; walk = walk->next) + { sp = walk->entry; + if (sp->type != 0 + && sp->type != LABEL + && strlen((const char *)sp->bscp) > 1) + { if (sp->context) + { m = (char *) emalloc(strlen((const char *)sp->bscp) + 1); + sprintf(m, "_%d_", sp->context->sc); + if (strcmp((const char *) m, (const char *) sp->bscp) == 0) + { continue; + /* 6.2.0: only prepend scope for inner-blocks, + not for top-level locals within a proctype + this means that you can no longer use the same name + for a global and a (top-level) local variable + */ + } } + + n = (char *) emalloc(strlen((const char *)sp->name) + + strlen((const char *)sp->bscp) + 1); + sprintf(n, "%s%s", sp->bscp, sp->name); + sp->name = n; /* discard the old memory */ + } } +} + Symbol * lookup(char *s) { Symbol *sp; Ordered *no; - int h = hash(s); + unsigned int h = hash(s); - for (sp = symtab[h]; sp; sp = sp->next) - if (strcmp(sp->name, s) == 0 - && samename(sp->context, context) - && samename(sp->owner, owner)) - return sp; /* found */ + if (old_scope_rules) + { /* same scope - global refering to global or local to local */ + for (sp = symtab[h]; sp; sp = sp->next) + { if (strcmp(sp->name, s) == 0 + && samename(sp->context, context) + && samename(sp->owner, owner)) + { return sp; /* found */ + } } + } else + { /* added 6.0.0: more traditional, scope rule */ + for (sp = symtab[h]; sp; sp = sp->next) + { if (strcmp(sp->name, s) == 0 + && samename(sp->context, context) + && (strcmp((const char *)sp->bscp, CurScope) == 0 + || strncmp((const char *)sp->bscp, CurScope, strlen((const char *)sp->bscp)) == 0) + && samename(sp->owner, owner)) + { + if (!samename(sp->owner, owner)) + { printf("spin: different container %s\n", sp->name); + printf(" old: %s\n", sp->owner?sp->owner->name:"--"); + printf(" new: %s\n", owner?owner->name:"--"); + /* alldone(1); */ + } + return sp; /* found */ + } } } - if (context) /* in proctype */ + if (context) /* in proctype, refers to global */ for (sp = symtab[h]; sp; sp = sp->next) - if (strcmp(sp->name, s) == 0 + { if (strcmp(sp->name, s) == 0 && !sp->context && samename(sp->owner, owner)) - return sp; /* global */ + { return sp; /* global */ + } } sp = (Symbol *) emalloc(sizeof(Symbol)); - sp->name = (char *) emalloc((int) strlen(s) + 1); + sp->name = (char *) emalloc(strlen(s) + 1); strcpy(sp->name, s); sp->nel = 1; sp->setat = depth; sp->context = context; sp->owner = owner; /* if fld in struct */ + sp->bscp = (unsigned char *) emalloc(strlen((const char *)CurScope)+1); + strcpy((char *)sp->bscp, CurScope); if (NamesNotAdded == 0) { sp->next = symtab[h]; @@ -109,8 +169,6 @@ trackvar(Lextok *n, Lextok *m) } } -Lextok *runstmnts = ZN; - void trackrun(Lextok *n) { @@ -151,11 +209,11 @@ checkrun(Symbol *parnm, int posno) strcpy(buf2, (!(res&4))?"bit":"byte"); sputtype(buf, parnm->type); i = (int) strlen(buf); - while (buf[--i] == ' ') buf[i] = '\0'; - if (strcmp(buf, buf2) == 0) return; + while (i > 0 && buf[--i] == ' ') buf[i] = '\0'; + if (i == 0 || strcmp(buf, buf2) == 0) return; prehint(parnm); printf("proctype %s, '%s %s' could be declared", - parnm->context->name, buf, parnm->name); + parnm->context?parnm->context->name:"", buf, parnm->name); printf(" '%s %s'\n", buf2, parnm->name); } } @@ -178,9 +236,9 @@ setptype(Lextok *n, int t, Lextok *vis) /* predefined types */ while (n) { if (n->sym->type && !(n->sym->hidden&32)) - { lineno = n->ln; Fname = n->fn; - non_fatal("redeclaration of '%s'", n->sym->name); - lineno = oln; + { lineno = n->ln; Fname = n->fn; + fatal("redeclaration of '%s'", n->sym->name); + lineno = oln; } n->sym->type = (short) t; @@ -201,14 +259,15 @@ setptype(Lextok *n, int t, Lextok *vis) /* predefined types */ n->sym->name); } if (vis) - { if (strncmp(vis->sym->name, ":hide:", 6) == 0) + { if (strncmp(vis->sym->name, ":hide:", (size_t) 6) == 0) { n->sym->hidden |= 1; + has_hidden++; if (t == BIT) fatal("bit variable (%s) cannot be hidden", n->sym->name); - } else if (strncmp(vis->sym->name, ":show:", 6) == 0) + } else if (strncmp(vis->sym->name, ":show:", (size_t) 6) == 0) { n->sym->hidden |= 2; - } else if (strncmp(vis->sym->name, ":local:", 7) == 0) + } else if (strncmp(vis->sym->name, ":local:", (size_t) 7) == 0) { n->sym->hidden |= 64; } } @@ -268,7 +327,13 @@ void setxus(Lextok *p, int t) { Lextok *m, *n; - has_xu = 1; + has_xu = 1; + + if (m_loss && t == XS) + { printf("spin: %s:%d, warning, xs tag not compatible with -m (message loss)\n", + (p->fn != NULL) ? p->fn->name : "stdin", p->ln); + } + if (!context) { lineno = p->ln; Fname = p->fn; @@ -276,6 +341,7 @@ setxus(Lextok *p, int t) } for (m = p; m; m = m->rgt) { Lextok *Xu_new = (Lextok *) emalloc(sizeof(Lextok)); + Xu_new->uiid = p->uiid; Xu_new->val = t; Xu_new->lft = m->lft; Xu_new->sym = context; @@ -297,8 +363,6 @@ setxus(Lextok *p, int t) } } -Lextok *Mtype = (Lextok *) 0; - void setmtype(Lextok *m) { Lextok *n; @@ -332,7 +396,7 @@ setmtype(Lextok *m) } lineno = oln; if (cnt > 256) - fatal("too many mtype elements (>255)", (char *)0); + fatal("too many mtype elements (>255)", (char *)0); } int @@ -389,11 +453,11 @@ symvar(Symbol *sp) printf("\t"); if (sp->owner) printf("%s.", sp->owner->name); printf("%s", sp->name); - if (sp->nel > 1) printf("[%d]", sp->nel); + if (sp->nel > 1 || sp->isarray == 1) printf("[%d]", sp->nel); if (sp->type == CHAN) printf("\t%d", (sp->ini)?sp->ini->val:0); - else if (sp->type == STRUCT) /* Frank Weil, 2.9.8 */ + else if (sp->type == STRUCT && sp->Snm != NULL) /* Frank Weil, 2.9.8 */ printf("\t%s", sp->Snm->name); else printf("\t%d", eval(sp->ini)); @@ -408,8 +472,13 @@ symvar(Symbol *sp) if (sp->Nid < 0) /* formal parameter */ printf("\t", -(sp->Nid)); + else if (sp->type == MTYPE) + printf("\t"); + else if (sp->isarray) + printf("\t"); else printf("\t"); + if (sp->type == CHAN && sp->ini) { int i; for (m = sp->ini->rgt, i = 0; m; m = m->rgt) @@ -423,6 +492,11 @@ symvar(Symbol *sp) if (m->rgt) printf("\t"); } } + + if (!old_scope_rules) + { printf("\t{scope %s}", sp->bscp); + } + printf("\n"); } @@ -440,11 +514,10 @@ chname(Symbol *sp) if (sp->context) printf("%s-", sp->context->name); if (sp->owner) printf("%s.", sp->owner->name); printf("%s", sp->name); - if (sp->nel > 1) printf("[%d]", sp->nel); + if (sp->nel > 1 || sp->isarray == 1) printf("[%d]", sp->nel); printf("\t"); } - static struct X { int typ; char *nm; } xx[] = { @@ -521,14 +594,14 @@ chanaccess(void) if (!(verbose&32) || has_code) continue; - printf("spin: warning, %s, ", Fname->name); + printf("spin: %s:0, warning, ", Fname->name); sputtype(buf, walk->entry->type); if (walk->entry->context) printf("proctype %s", walk->entry->context->name); else printf("global"); - printf(", '%s%s' variable is never used\n", + printf(", '%s%s' variable is never used (other than in print stmnts)\n", buf, walk->entry->name); } } } diff --git a/sys/src/cmd/spin/tl.h b/sys/src/cmd/spin/tl.h index eaa2056c8..7716be19c 100644 --- a/sys/src/cmd/spin/tl.h +++ b/sys/src/cmd/spin/tl.h @@ -1,16 +1,13 @@ /***** tl_spin: tl.h *****/ -/* Copyright (c) 1995-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 */ - -/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ -/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + * + * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, + * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. + */ #include #include @@ -66,6 +63,7 @@ enum { #ifdef NXT , NEXT /* 269 */ #endif + , CEXPR /* 270 */ }; Node *Canonical(Node *); @@ -82,11 +80,12 @@ Symbol *tl_lookup(char *); Symbol *getsym(Symbol *); Symbol *DoDump(Node *); -char *emalloc(int); /* in main.c */ +extern char *emalloc(size_t); /* in main.c */ + +extern unsigned int hash(const char *); /* in sym.c */ int anywhere(int, Node *, Node *); int dump_cond(Node *, Node *, int); -int hash(char *); /* in sym.c */ int isalnum_(int); /* in spinlex.c */ int isequal(Node *, Node *); int tl_Getchar(void); @@ -100,6 +99,10 @@ void exit(int); void Fatal(char *, char *); void fatal(char *, char *); void fsm_print(void); +void ini_buchi(void); +void ini_cache(void); +void ini_rewrt(void); +void ini_trans(void); void releasenode(int, Node *); void tfree(void *); void tl_explain(int); diff --git a/sys/src/cmd/spin/tl_buchi.c b/sys/src/cmd/spin/tl_buchi.c index 161661950..c7a9d2bf4 100644 --- a/sys/src/cmd/spin/tl_buchi.c +++ b/sys/src/cmd/spin/tl_buchi.c @@ -1,20 +1,18 @@ /***** tl_spin: tl_buchi.c *****/ -/* Copyright (c) 1995-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 */ - -/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ -/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + * + * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, + * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. + */ #include "tl.h" extern int tl_verbose, tl_clutter, Total, Max_Red; +extern char *claim_name; FILE *tl_out; /* if standalone: = stdout; */ @@ -38,6 +36,13 @@ typedef struct State { static State *never = (State *) 0; static int hitsall; +void +ini_buchi(void) +{ + never = (State *) 0; + hitsall = 0; +} + static int sametrans(Transition *s, Transition *t) { @@ -58,6 +63,7 @@ Prune(Node *p) #ifdef NXT case NEXT: #endif + case CEXPR: return p; case OR: p->lft = Prune(p->lft); @@ -545,10 +551,22 @@ rev_trans(Transition *t) /* print transitions in reverse order... */ rev_trans(t->nxt); if (t->redundant && !tl_verbose) return; - fprintf(tl_out, "\t:: ("); - if (dump_cond(t->cond, t->cond, 1)) - fprintf(tl_out, "1"); - fprintf(tl_out, ") -> goto %s\n", t->name->name); + + if (strcmp(t->name->name, "accept_all") == 0) /* 6.2.4 */ + { /* not d_step because there may be remote refs */ + fprintf(tl_out, "\t:: atomic { ("); + if (dump_cond(t->cond, t->cond, 1)) + fprintf(tl_out, "1"); + fprintf(tl_out, ") -> assert(!("); + if (dump_cond(t->cond, t->cond, 1)) + fprintf(tl_out, "1"); + fprintf(tl_out, ")) }\n"); + } else + { fprintf(tl_out, "\t:: ("); + if (dump_cond(t->cond, t->cond, 1)) + fprintf(tl_out, "1"); + fprintf(tl_out, ") -> goto %s\n", t->name->name); + } tcnt++; } @@ -570,11 +588,11 @@ printstate(State *b) && Max_Red == 0) fprintf(tl_out, "T0%s:\n", &(b->name->name[6])); - fprintf(tl_out, "\tif\n"); + fprintf(tl_out, "\tdo\n"); tcnt = 0; rev_trans(b->trans); if (!tcnt) fprintf(tl_out, "\t:: false\n"); - fprintf(tl_out, "\tfi;\n"); + fprintf(tl_out, "\tod;\n"); Total++; } @@ -626,13 +644,13 @@ fsm_print(void) if (tl_clutter) clutter(); b = findstate("T0_init"); - if (Max_Red == 0) + if (b && (Max_Red == 0)) b->accepting = 1; mergestates(0); b = findstate("T0_init"); - fprintf(tl_out, "never { /* "); + fprintf(tl_out, "never %s { /* ", claim_name?claim_name:""); put_uform(); fprintf(tl_out, " */\n"); diff --git a/sys/src/cmd/spin/tl_cache.c b/sys/src/cmd/spin/tl_cache.c index fc902dcb0..1cf027353 100644 --- a/sys/src/cmd/spin/tl_cache.c +++ b/sys/src/cmd/spin/tl_cache.c @@ -1,16 +1,13 @@ /***** tl_spin: tl_cache.c *****/ -/* Copyright (c) 1995-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 */ - -/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ -/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + * + * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, + * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. + */ #include "tl.h" @@ -24,9 +21,18 @@ typedef struct Cache { static Cache *stored = (Cache *) 0; static unsigned long Caches, CacheHits; -static int ismatch(Node *, Node *); +static int ismatch(Node *, Node *); +static int sameform(Node *, Node *); + extern void fatal(char *, char *); -int sameform(Node *, Node *); + +void +ini_cache(void) +{ + stored = (Cache *) 0; + Caches = 0; + CacheHits = 0; +} #if 0 void @@ -182,7 +188,7 @@ sametrees(int ntyp, Node *a, Node *b) return all_lfts(ntyp, b, a); } -int /* a better isequal() */ +static int /* a better isequal() */ sameform(Node *a, Node *b) { if (!a && !b) return 1; @@ -206,6 +212,7 @@ sameform(Node *a, Node *b) #ifdef NXT case NEXT: #endif + case CEXPR: return sameform(a->lft, b->lft); case U_OPER: case V_OPER: diff --git a/sys/src/cmd/spin/tl_lex.c b/sys/src/cmd/spin/tl_lex.c index 110e06eae..7b08e1f65 100644 --- a/sys/src/cmd/spin/tl_lex.c +++ b/sys/src/cmd/spin/tl_lex.c @@ -1,16 +1,13 @@ /***** tl_spin: tl_lex.c *****/ -/* Copyright (c) 1995-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 */ - -/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ -/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + * + * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, + * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. + */ #include #include @@ -18,6 +15,7 @@ static Symbol *symtab[Nhash+1]; static int tl_lex(void); +extern int tl_peek(int); extern YYSTYPE tl_yylval; extern char yytext[]; @@ -26,11 +24,19 @@ extern char yytext[]; static void tl_getword(int first, int (*tst)(int)) -{ int i=0; char c; +{ int i=0; int c; yytext[i++] = (char ) first; - while (tst(c = tl_Getchar())) - yytext[i++] = c; + + c = tl_Getchar(); + while (c != -1 && tst(c)) + { yytext[i++] = (char) c; + c = tl_Getchar(); + } + +/* while (tst(c = tl_Getchar())) + * yytext[i++] = c; + */ yytext[i] = '\0'; tl_UnGetchar(); } @@ -54,11 +60,85 @@ int tl_yylex(void) { int c = tl_lex(); #if 0 - printf("c = %d\n", c); + printf("c = %c (%d)\n", c, c); #endif return c; } +static int +is_predicate(int z) +{ char c, c_prev = z; + char want = (z == '{') ? '}' : ')'; + int i = 0, j, nesting = 0; + char peek_buf[512]; + + c = tl_peek(i++); /* look ahead without changing position */ + while ((c != want || nesting > 0) && c != -1 && i < 2047) + { if (islower((int) c) || c == '_') + { peek_buf[0] = c; + j = 1; + while (j < (int) sizeof(peek_buf) + && (isalnum((int)(c = tl_peek(i))) || c == '_')) + { peek_buf[j++] = c; + i++; + } + c = 0; /* make sure we don't match on z or want on the peekahead */ + if (j >= (int) sizeof(peek_buf)) + { peek_buf[j-1] = '\0'; + fatal("name '%s' in ltl formula too long", peek_buf); + } + peek_buf[j] = '\0'; + if (strcmp(peek_buf, "always") == 0 + || strcmp(peek_buf, "equivalent") == 0 + || strcmp(peek_buf, "eventually") == 0 + || strcmp(peek_buf, "until") == 0 + || strcmp(peek_buf, "next") == 0 + || strcmp(peek_buf, "c_expr") == 0) + { return 0; + } + } else + { int c_nxt = tl_peek(i); + if (((c == 'U' || c == 'V' || c == 'X') + && !isalnum_(c_prev) + && (c_nxt == -1 || !isalnum_(c_nxt))) + || (c == '<' && c_nxt == '>') + || (c == '<' && c_nxt == '-') + || (c == '-' && c_nxt == '>') + || (c == '[' && c_nxt == ']')) + { return 0; + } } + + if (c == z) + { nesting++; + } + if (c == want) + { nesting--; + } + c_prev = c; + c = tl_peek(i++); + } + return 1; +} + +static void +read_upto_closing(int z) +{ char c, want = (z == '{') ? '}' : ')'; + int i = 0, nesting = 0; + + c = tl_Getchar(); + while ((c != want || nesting > 0) && c != -1 && i < 2047) /* yytext is 2048 */ + { yytext[i++] = c; + if (c == z) + { nesting++; + } + if (c == want) + { nesting--; + } + c = tl_Getchar(); + } + yytext[i] = '\0'; +} + static int tl_lex(void) { int c; @@ -74,6 +154,20 @@ tl_lex(void) } while (c == ' '); /* '\t' is removed in tl_main.c */ + if (c == '{' || c == '(') /* new 6.0.0 */ + { if (is_predicate(c)) + { read_upto_closing(c); + tl_yylval = tl_nn(PREDICATE,ZN,ZN); + if (!tl_yylval) + { fatal("unexpected error 4", (char *) 0); + } + tl_yylval->sym = tl_lookup(yytext); + return PREDICATE; + } } + + if (c == '}') + { tl_yyerror("unexpected '}'"); + } if (islower(c)) { tl_getword(c, isalnum_); if (strcmp("true", yytext) == 0) @@ -82,10 +176,34 @@ tl_lex(void) if (strcmp("false", yytext) == 0) { Token(FALSE); } + if (strcmp("always", yytext) == 0) + { Token(ALWAYS); + } + if (strcmp("eventually", yytext) == 0) + { Token(EVENTUALLY); + } + if (strcmp("until", yytext) == 0) + { Token(U_OPER); + } +#ifdef NXT + if (strcmp("next", yytext) == 0) + { Token(NEXT); + } +#endif + if (strcmp("c_expr", yytext) == 0) + { Token(CEXPR); + } + if (strcmp("not", yytext) == 0) + { Token(NOT); + } tl_yylval = tl_nn(PREDICATE,ZN,ZN); + if (!tl_yylval) + { fatal("unexpected error 5", (char *) 0); + } tl_yylval->sym = tl_lookup(yytext); return PREDICATE; } + if (c == '<') { c = tl_Getchar(); if (c == '>') @@ -124,7 +242,7 @@ tl_lex(void) Symbol * tl_lookup(char *s) { Symbol *sp; - int h = hash(s); + unsigned int h = hash(s); for (sp = symtab[h]; sp; sp = sp->next) if (strcmp(sp->name, s) == 0) diff --git a/sys/src/cmd/spin/tl_main.c b/sys/src/cmd/spin/tl_main.c index 10ab0e9bd..667834265 100644 --- a/sys/src/cmd/spin/tl_main.c +++ b/sys/src/cmd/spin/tl_main.c @@ -1,16 +1,13 @@ /***** tl_spin: tl_main.c *****/ -/* Copyright (c) 1995-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 */ - -/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ -/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + * + * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, + * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. + */ #include "tl.h" @@ -21,7 +18,10 @@ int tl_errs = 0; int tl_verbose = 0; int tl_terse = 0; int tl_clutter = 0; +int state_cnt = 0; + unsigned long All_Mem = 0; +char *claim_name; static char uform[4096]; static int hasuform=0, cnt=0; @@ -38,6 +38,15 @@ tl_Getchar(void) return -1; } +int +tl_peek(int n) +{ + if (cnt+n < hasuform) + { return uform[cnt+n]; + } + return -1; +} + void tl_balanced(void) { int i; @@ -45,10 +54,21 @@ tl_balanced(void) for (i = 0; i < hasuform; i++) { if (uform[i] == '(') - { k++; + { if (i > 0 + && ((uform[i-1] == '"' && uform[i+1] == '"') + || (uform[i-1] == '\'' && uform[i+1] == '\''))) + { continue; + } + k++; } else if (uform[i] == ')') - { k--; + { if (i > 0 + && ((uform[i-1] == '"' && uform[i+1] == '"') + || (uform[i-1] == '\'' && uform[i+1] == '\''))) + { continue; + } + k--; } } + if (k != 0) { tl_errs++; tl_yyerror("parentheses not balanced"); @@ -79,18 +99,40 @@ tl_stats(void) int tl_main(int argc, char *argv[]) { int i; - extern int verbose, xspin; - tl_verbose = verbose; - tl_clutter = 1-xspin; /* use -X -f to turn off uncluttering */ + extern int xspin, s_trail; + + tl_verbose = 0; /* was: tl_verbose = verbose; */ + if (xspin && s_trail) + { tl_clutter = 1; + /* generating claims for a replay should + be done the same as when generating the + pan.c that produced the error-trail */ + } else + { tl_clutter = 1-xspin; /* use -X -f to turn off uncluttering */ + } + newstates = 0; + state_cnt = 0; + tl_errs = 0; + tl_terse = 0; + All_Mem = 0; + memset(uform, 0, sizeof(uform)); + hasuform=0; + cnt=0; + claim_name = (char *) 0; + + ini_buchi(); + ini_cache(); + ini_rewrt(); + ini_trans(); while (argc > 1 && argv[1][0] == '-') - { switch (argv[1][1]) { + { + switch (argv[1][1]) { case 'd': newstates = 1; /* debugging mode */ break; case 'f': argc--; argv++; - for (i = 0; i < argv[1][i]; i++) + for (i = 0; argv[1][i]; i++) { if (argv[1][i] == '\t' - || argv[1][i] == '\"' || argv[1][i] == '\n') argv[1][i] = ' '; } @@ -101,6 +143,10 @@ tl_main(int argc, char *argv[]) break; case 'n': tl_terse = 1; break; + case 'c': argc--; argv++; + claim_name = (char *) emalloc(strlen(argv[1])+1); + strcpy(claim_name, argv[1]); + break; default : printf("spin -f: saw '-%c'\n", argv[1][1]); goto nogood; } @@ -162,6 +208,12 @@ dump(Node *n) case PREDICATE: fprintf(tl_out, "(%s)", n->sym->name); break; + case CEXPR: + fprintf(tl_out, "c_expr"); + fprintf(tl_out, " {"); + dump(n->lft); + fprintf(tl_out, "}"); + break; case -1: fprintf(tl_out, " D "); break; @@ -189,6 +241,7 @@ tl_explain(int n) #ifdef NXT case NEXT: printf("X"); break; #endif + case CEXPR: printf("c_expr"); break; case TRUE: printf("true"); break; case FALSE: printf("false"); break; case ';': printf("end of formula"); break; @@ -202,10 +255,14 @@ tl_non_fatal(char *s1, char *s2) int i; printf("tl_spin: "); +#if 1 + printf(s1, s2); /* prevent a compiler warning */ +#else if (s2) printf(s1, s2); else printf(s1); +#endif if (tl_yychar != -1 && tl_yychar != 0) { printf(", saw '"); tl_explain(tl_yychar); diff --git a/sys/src/cmd/spin/tl_mem.c b/sys/src/cmd/spin/tl_mem.c index 52021e466..f9d805350 100644 --- a/sys/src/cmd/spin/tl_mem.c +++ b/sys/src/cmd/spin/tl_mem.c @@ -1,16 +1,13 @@ /***** tl_spin: tl_mem.c *****/ -/* Copyright (c) 1995-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 */ - -/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ -/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + * + * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, + * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. + */ #include "tl.h" diff --git a/sys/src/cmd/spin/tl_parse.c b/sys/src/cmd/spin/tl_parse.c index 6206a0d99..6a16017ec 100644 --- a/sys/src/cmd/spin/tl_parse.c +++ b/sys/src/cmd/spin/tl_parse.c @@ -1,16 +1,13 @@ /***** tl_spin: tl_parse.c *****/ -/* Copyright (c) 1995-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 */ - -/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ -/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + * + * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, + * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. + */ #include "tl.h" @@ -44,11 +41,13 @@ tl_factor(void) ptr = tl_yylval; tl_yychar = tl_yylex(); ptr->lft = tl_factor(); + if (!ptr->lft) + { fatal("malformed expression", (char *) 0); + } ptr = push_negation(ptr); break; case ALWAYS: tl_yychar = tl_yylex(); - ptr = tl_factor(); #ifndef NO_OPT if (ptr->ntyp == FALSE @@ -73,6 +72,14 @@ tl_factor(void) ptr = tl_nn(NEXT, ptr, ZN); break; #endif + case CEXPR: + tl_yychar = tl_yylex(); + ptr = tl_factor(); + if (ptr->ntyp != PREDICATE) + { tl_yyerror("expected {...} after c_expr"); + } + ptr = tl_nn(CEXPR, ptr, ZN); + break; case EVENTUALLY: tl_yychar = tl_yylex(); @@ -385,7 +392,10 @@ tl_formula(void) void tl_parse(void) -{ Node *n = tl_formula(); +{ Node *n; + + /* tl_verbose = 1; */ + n = tl_formula(); if (tl_verbose) { printf("formula: "); dump(n); diff --git a/sys/src/cmd/spin/tl_rewrt.c b/sys/src/cmd/spin/tl_rewrt.c index 6e00d9ac0..ddc437260 100644 --- a/sys/src/cmd/spin/tl_rewrt.c +++ b/sys/src/cmd/spin/tl_rewrt.c @@ -1,16 +1,13 @@ /***** tl_spin: tl_rewrt.c *****/ -/* Copyright (c) 1995-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 */ - -/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ -/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + * + * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, + * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. + */ #include "tl.h" @@ -18,6 +15,12 @@ extern int tl_verbose; static Node *can = ZN; +void +ini_rewrt(void) +{ + can = ZN; +} + Node * right_linked(Node *n) { @@ -137,6 +140,9 @@ addcan(int tok, Node *n) } s = DoDump(N); + if (!s) + { fatal("unexpected error 6", (char *) 0); + } if (can->ntyp != tok) /* only one element in list so far */ { ptr = &can; goto insert; @@ -146,7 +152,10 @@ addcan(int tok, Node *n) prev = ZN; for (m = can; m->ntyp == tok && m->rgt; prev = m, m = m->rgt) { t = DoDump(m->lft); - cmp = strcmp(s->name, t->name); + if (t != ZS) + cmp = strcmp(s->name, t->name); + else + cmp = 0; if (cmp == 0) /* duplicate */ return; if (cmp < 0) diff --git a/sys/src/cmd/spin/tl_trans.c b/sys/src/cmd/spin/tl_trans.c index 72964ca6b..ed5b5878a 100644 --- a/sys/src/cmd/spin/tl_trans.c +++ b/sys/src/cmd/spin/tl_trans.c @@ -1,21 +1,18 @@ /***** tl_spin: tl_trans.c *****/ -/* Copyright (c) 1995-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 */ - -/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */ -/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + * + * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, + * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. + */ #include "tl.h" extern FILE *tl_out; -extern int tl_errs, tl_verbose, tl_terse, newstates; +extern int tl_errs, tl_verbose, tl_terse, newstates, state_cnt; int Stack_mx=0, Max_Red=0, Total=0; @@ -23,7 +20,7 @@ static Mapping *Mapped = (Mapping *) 0; static Graph *Nodes_Set = (Graph *) 0; static Graph *Nodes_Stack = (Graph *) 0; -static char dumpbuf[2048]; +static char dumpbuf[4096]; static int Red_cnt = 0; static int Lab_cnt = 0; static int Base = 0; @@ -51,6 +48,24 @@ static void ng(Symbol *, Symbol *, Node *, Node *, Node *); static void push_stack(Graph *); static void sdump(Node *); +void +ini_trans(void) +{ + Stack_mx = 0; + Max_Red = 0; + Total = 0; + + Mapped = (Mapping *) 0; + Nodes_Set = (Graph *) 0; + Nodes_Stack = (Graph *) 0; + + memset(dumpbuf, 0, sizeof(dumpbuf)); + Red_cnt = 0; + Lab_cnt = 0; + Base = 0; + Stack_sz = 0; +} + static void dump_graph(Graph *g) { Node *n1; @@ -101,9 +116,8 @@ pop_stack(void) static char * newname(void) -{ static int cnt = 0; - static char buf[32]; - sprintf(buf, "S%d", cnt++); +{ static char buf[32]; + sprintf(buf, "S%d", state_cnt++); return buf; } @@ -132,6 +146,8 @@ static void mk_grn(Node *n) { Graph *p; + if (!n) return; + n = right_linked(n); more: for (p = Nodes_Set; p; p = p->nxt) @@ -152,6 +168,8 @@ static void mk_red(Node *n) { Graph *p; + if (!n) return; + n = right_linked(n); for (p = Nodes_Set; p; p = p->nxt) { if (p->outgoing @@ -240,6 +258,15 @@ dump_cond(Node *pp, Node *r, int first) q = dupnode(pp); q = rewrite(q); + if (q->ntyp == CEXPR) + { if (!frst) fprintf(tl_out, " && "); + fprintf(tl_out, "c_expr { "); + dump_cond(q->lft, r, 1); + fprintf(tl_out, " } "); + frst = 0; + return frst; + } + if (q->ntyp == PREDICATE || q->ntyp == NOT #ifndef NXT @@ -342,7 +369,7 @@ static void fsm_trans(Graph *p, int count, char *curnm) { Graph *r; Symbol *s; - char prefix[128], nwnm[128]; + char prefix[128], nwnm[256]; if (!p->outgoing) addtrans(p, curnm, False, "accept_all"); @@ -452,9 +479,11 @@ fixinit(Node *orig) ng(tl_lookup("init"), ZS, ZN, ZN, ZN); p1 = pop_stack(); - p1->nxt = Nodes_Set; - p1->Other = p1->Old = orig; - Nodes_Set = p1; + if (p1) + { p1->nxt = Nodes_Set; + p1->Other = p1->Old = orig; + Nodes_Set = p1; + } for (g = Nodes_Set; g; g = g->nxt) { for (q1 = g->incoming; q1; q1 = q2) @@ -532,6 +561,10 @@ common1: sdump(n->lft); case NEXT: strcat(dumpbuf, "X"); goto common1; #endif + case CEXPR: strcat(dumpbuf, "c_expr {"); + sdump(n->lft); + strcat(dumpbuf, "}"); + break; case NOT: strcat(dumpbuf, "!"); goto common1; case TRUE: strcat(dumpbuf, "T"); @@ -718,10 +751,13 @@ out: break; case PREDICATE: case NOT: + case CEXPR: if (can_release) releasenode(1, now); push_stack(g); break; case V_OPER: + Assert(now->rgt != ZN, now->ntyp); + Assert(now->lft != ZN, now->ntyp); Assert(now->rgt->nxt == ZN, now->ntyp); Assert(now->lft->nxt == ZN, now->ntyp); n1 = now->rgt; @@ -759,6 +795,7 @@ out: #ifdef NXT case NEXT: + Assert(now->lft != ZN, now->ntyp); nx = dupnode(now->lft); nx->nxt = g->Next; g->Next = nx; diff --git a/sys/src/cmd/spin/vars.c b/sys/src/cmd/spin/vars.c index e83d74f57..5c73b09f6 100644 --- a/sys/src/cmd/spin/vars.c +++ b/sys/src/cmd/spin/vars.c @@ -1,13 +1,10 @@ /***** spin: vars.c *****/ -/* Copyright (c) 1989-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 */ +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ #include "spin.h" #include "y.tab.h" @@ -17,7 +14,7 @@ extern RunList *X, *LastX; extern Symbol *Fname; extern char Buf[]; extern int lineno, depth, verbose, xspin, limited_vis; -extern int analyze, jumpsteps, nproc, nstop, columns; +extern int analyze, jumpsteps, nproc, nstop, columns, old_priority_rules; extern short no_arrays, Have_claim; extern void sr_mesg(FILE *, int, int); extern void sr_buf(int, int); @@ -42,22 +39,54 @@ getval(Lextok *sn) { if (!X) return 0; return X->pid - Have_claim; } + if (strcmp(s->name, "_priority") == 0) + { if (!X) return 0; + + if (old_priority_rules) + { non_fatal("cannot refer to _priority with -o6", (char *) 0); + return 1; + } + return X->priority; + } + if (strcmp(s->name, "_nr_pr") == 0) - return nproc-nstop; /* new 3.3.10 */ + { return nproc-nstop; /* new 3.3.10 */ + } if (s->context && s->type) - return getlocal(sn); + { return getlocal(sn); + } if (!s->type) /* not declared locally */ { s = lookup(s->name); /* try global */ sn->sym = s; /* fix it */ } + return getglobal(sn); } int setval(Lextok *v, int n) { + if (strcmp(v->sym->name, "_last") == 0 + || strcmp(v->sym->name, "_p") == 0 + || strcmp(v->sym->name, "_pid") == 0 + || strcmp(v->sym->name, "_nr_qs") == 0 + || strcmp(v->sym->name, "_nr_pr") == 0) + { non_fatal("illegal assignment to %s", v->sym->name); + } + if (strcmp(v->sym->name, "_priority") == 0) + { if (old_priority_rules) + { non_fatal("cannot refer to _priority with -o6", (char *) 0); + return 1; + } + if (!X) + { non_fatal("no context for _priority", (char *) 0); + return 1; + } + X->priority = n; + } + if (v->sym->context && v->sym->type) return setlocal(v, n); if (!v->sym->type) @@ -90,6 +119,7 @@ int checkvar(Symbol *s, int n) { int i, oln = lineno; /* calls on eval() change it */ Symbol *ofnm = Fname; + Lextok *z, *y; if (!in_bound(s, n)) return 0; @@ -101,15 +131,23 @@ checkvar(Symbol *s, int n) /* not a STRUCT */ if (s->val == (int *) 0) /* uninitialized */ { s->val = (int *) emalloc(s->nel*sizeof(int)); + z = s->ini; for (i = 0; i < s->nel; i++) - { if (s->type != CHAN) - { rm_selfrefs(s, s->ini); - s->val[i] = eval(s->ini); + { if (z && z->ntyp == ',') + { y = z->lft; + z = z->rgt; + } else + { y = z; + } + if (s->type != CHAN) + { rm_selfrefs(s, y); + s->val[i] = eval(y); } else if (!analyze) - s->val[i] = qmake(s); - } } + { s->val[i] = qmake(s); + } } } lineno = oln; Fname = ofnm; + return 1; } @@ -118,14 +156,16 @@ getglobal(Lextok *sn) { Symbol *s = sn->sym; int i, n = eval(sn->lft); - if (s->type == 0 && X && (i = find_lab(s, X->n, 0))) + if (s->type == 0 && X && (i = find_lab(s, X->n, 0))) /* getglobal */ { printf("findlab through getglobal on %s\n", s->name); return i; /* can this happen? */ } if (s->type == STRUCT) - return Rval_struct(sn, s, 1); /* 1 = check init */ + { return Rval_struct(sn, s, 1); /* 1 = check init */ + } if (checkvar(s, n)) - return cast_val(s->type, s->val[n], s->nbits); + { return cast_val(s->type, s->val[n], s->nbits); + } return 0; } @@ -145,23 +185,26 @@ cast_val(int t, int v, int w) } if (v != i+s+ (int) u) - { char buf[32]; sprintf(buf, "%d->%d (%d)", v, i+s+u, t); + { char buf[64]; sprintf(buf, "%d->%d (%d)", v, i+s+(int)u, t); non_fatal("value (%s) truncated in assignment", buf); } - return (int)(i+s+u); + return (int)(i+s+(int)u); } static int setglobal(Lextok *v, int m) { if (v->sym->type == STRUCT) - (void) Lval_struct(v, v->sym, 1, m); - else + { (void) Lval_struct(v, v->sym, 1, m); + } else { int n = eval(v->lft); if (checkvar(v->sym, n)) - { v->sym->val[n] = cast_val(v->sym->type, m, v->sym->nbits); - v->sym->setat = depth; - } } + { int oval = v->sym->val[n]; + int nval = cast_val(v->sym->type, m, v->sym->nbits); + v->sym->val[n] = nval; + if (oval != nval) + { v->sym->setat = depth; + } } } return 1; } @@ -215,7 +258,12 @@ dumpglobals(void) continue; if (sp->type == STRUCT) - { dump_struct(sp, sp->name, 0); + { if ((verbose&4) && !(verbose&64) + && (sp->setat < depth + && jumpsteps != depth)) + { continue; + } + dump_struct(sp, sp->name, 0); continue; } for (j = 0; j < sp->nel; j++) @@ -227,13 +275,15 @@ dumpglobals(void) if ((verbose&4) && !(verbose&64) && (sp->setat < depth && jumpsteps != depth)) - continue; + { continue; + } + dummy->sym = sp; dummy->lft->val = j; /* in case of cast_val warnings, do this first: */ prefetch = getglobal(dummy); printf("\t\t%s", sp->name); - if (sp->nel > 1) printf("[%d]", j); + if (sp->nel > 1 || sp->isarray) printf("[%d]", j); printf(" = "); sr_mesg(stdout, prefetch, sp->type == MTYPE); @@ -249,7 +299,7 @@ dumpglobals(void) } sr_buf(prefetch, sp->type == MTYPE); if (sp->colnr == 0) - { sp->colnr = maxcolnr; + { sp->colnr = (unsigned char) maxcolnr; maxcolnr = 1+(maxcolnr%10); } colpos = nproc+sp->colnr-1; @@ -266,7 +316,7 @@ dumpglobals(void) depth, colpos); printf("(state 0)\t[printf('MSC: globvar\\\\n')]\n"); printf("\t\t%s", sp->name); - if (sp->nel > 1) printf("[%d]", j); + if (sp->nel > 1 || sp->isarray) printf("[%d]", j); printf(" = %s\n", Buf); } } } } @@ -303,8 +353,8 @@ dumplocal(RunList *r) dummy->lft->val = i; printf("\t\t%s(%d):%s", - r->n->name, r->pid, z->name); - if (z->nel > 1) printf("[%d]", i); + r->n->name, r->pid - Have_claim, z->name); + if (z->nel > 1 || z->isarray) printf("[%d]", i); printf(" = "); sr_mesg(stdout, getval(dummy), z->type == MTYPE); printf("\n"); @@ -321,7 +371,7 @@ dumplocal(RunList *r) } sr_buf(getval(dummy), z->type==MTYPE); if (z->colnr == 0) - { z->colnr = maxcolnr; + { z->colnr = (unsigned char) maxcolnr; maxcolnr = 1+(maxcolnr%10); } colpos = nproc+z->colnr-1; @@ -341,7 +391,7 @@ dumplocal(RunList *r) printf("(state 0)\t[printf('MSC: locvar\\\\n')]\n"); printf("\t\t%s(%d):%s", r->n->name, r->pid, z->name); - if (z->nel > 1) printf("[%d]", i); + if (z->nel > 1 || z->isarray) printf("[%d]", i); printf(" = %s\n", Buf); } } } } diff --git a/sys/src/cmd/spin/version.h b/sys/src/cmd/spin/version.h index 4ad23fa4a..769066420 100644 --- a/sys/src/cmd/spin/version.h +++ b/sys/src/cmd/spin/version.h @@ -1 +1,9 @@ -#define Version "Spin Version 4.3.0 -- 22 June 2007" +/***** spin: version.h *****/ + +/* + * This file is part of the public release of Spin. It is subject to the + * terms in the LICENSE file that is included in this source directory. + * Tool documentation is available at http://spinroot.com + */ + +#define SpinVersion "Spin Version 6.4.7 -- 19 August 2017"