Update Gerard Holzmann's Spin from version 4.3.0 (22 June 2007) to 6.1.0 (4 May 2011). The manual was carefully updated to reflect formatting differences. For information, here are the differences between the original version from Gerard Holzmann and this Plan 9 version of Spin. diff /sys/src/cmd/spin.orig/main.c /sys/src/cmd/spin/main.c 103c103 < #define CPP "/lib/cpp" /* classic Unix systems */ --- > #define CPP "/bin/cpp" /* classic Unix systems */ 540c540 < { extern int yychar; extern char yytext[]; --- > { extern char yytext[]; 548,552d547 < if (yychar > 0) < { printf(" saw '"); < explain(yychar); < printf("'"); < } diff /sys/src/cmd/spin.orig/pangen1.c /sys/src/cmd/spin/pangen1.c 19,23d18 < #ifdef SOLARIS < #include < #else < #include < #endif 157c152 < if (i <= UINT8_MAX) /* in stdint.h = UCHAR_MAX from limits.h */ --- > if (i <= 255) /* in stdint.h = UCHAR_MAX from limits.h */ 159c154 < } else if (i <= UINT16_MAX) /* really USHRT_MAX from limits.h */ --- > } else if (i <= 65535) /* really USHRT_MAX from limits.h */ diff /sys/src/cmd/spin.orig/spin.h /sys/src/cmd/spin/spin.h 18,20d17 < #ifndef PC < #include < #endif Reference: /n/sources/patch/applied/spin-610 Date: Thu Nov 17 15:38:18 CET 2011 Signed-off-by: djc@9grid.fr --- /sys/src/cmd/spin/dstep.c Thu Nov 17 15:26:34 2011 +++ /sys/src/cmd/spin/dstep.c Thu Nov 17 15:26:27 2011 @@ -12,7 +12,7 @@ #include "spin.h" #include "y.tab.h" -#define MAXDSTEP 1024 /* was 512 */ +#define MAXDSTEP 2048 /* was 512 */ char *NextLab[64]; int Level=0, GenCode=0, IsGuard=0, TestOnly=0; @@ -21,7 +21,7 @@ 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 +59,7 @@ 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", @@ -164,7 +164,7 @@ 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 +184,17 @@ 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; @@ -245,7 +245,7 @@ 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 +253,7 @@ 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; --- /sys/src/cmd/spin/flow.c Thu Nov 17 15:26:48 2011 +++ /sys/src/cmd/spin/flow.c Thu Nov 17 15:26:40 2011 @@ -13,12 +13,14 @@ #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; +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; static Lbreak *breakstack = (Lbreak *) 0; static Lextok *innermost; @@ -40,7 +42,10 @@ t = seqlist(s, cur_s); cur_s = t; - if (top) Elcnt = 1; + if (top) + { Elcnt = 1; + initialization_ok = 1; + } } void @@ -113,8 +118,8 @@ && 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,6 +152,10 @@ { Sequence *s = cur_s->this; Symbol *z; + if (nottop == 0) /* end of proctype body */ + { initialization_ok = 1; + } + if (nottop > 0 && (z = has_lab(s->frst, 0))) { printf("error: (%s:%d) label %s placed incorrectly\n", (s->frst->n)?s->frst->n->fn->name:"-", @@ -388,8 +397,13 @@ && 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--; } @@ -561,35 +575,71 @@ } void +show_lab(void) +{ Label *l; + for (l = labtab; l; l = l->nxt) + printf("label %s\n", l->s->name); +} + +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 + && l->uiid == cur_uiid) { non_fatal("label %s redeclared", s->name); break; - } + } } + 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 cur_uiid = n->uiid; + /* + * try to find a label with the same uiid + * but if it doesn't exist, return any other + * that is defined within the same scope + */ + for (l = labtab; l; l = l->nxt) + { if (strcmp(s->name, l->s->name) == 0 + && s->context == l->s->context) + { anymatch = l; + if (cur_uiid == l->uiid) /* best match */ + { return l; + } } } + + return anymatch; /* likely to be 0 */ +} + 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); + } + + if (md) + { lineno = n->ln; + Fname = n->fn; + fatal("undefined label %s", n->sym->name); + } - lineno = n->ln; - Fname = n->fn; - if (md) fatal("undefined label %s", s->name); return ZE; } @@ -735,6 +785,226 @@ } } +#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->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]; + /* 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 */ + + pushbreak(); + + /* 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 */ + + 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 +1017,16 @@ 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: warning, %s:%d, 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: warning, %s:%d, d_step inside ", + f->n->fn->name, f->n->ln); if (added) { printf("d_step (ignored)\n"); goto mknonat; @@ -770,8 +1040,8 @@ 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 +1059,11 @@ 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>\n", l->c->name); + else + printf("<%s i%d>\n", l->c->name, l->uiid); + } } --- /sys/src/cmd/spin/guided.c Thu Nov 17 15:26:57 2011 +++ /sys/src/cmd/spin/guided.c Thu Nov 17 15:26:52 2011 @@ -21,6 +21,7 @@ extern int nproc, nstop, Tval, ntrail, columns; extern short Have_claim, Skip_claim; extern void ana_src(int, int); +extern char **trailfilename; int TstOnly = 0, pno; @@ -88,10 +89,18 @@ * 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 */ @@ -188,16 +197,36 @@ pno - Have_claim, i, nst, dothis->n->ntyp); lost_trail(); } + + if (!xspin && (verbose&32)) + { printf("i=%d pno %d\n", i, pno); + } + 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 (step %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 + { X->pc = dothis; } - X->pc = dothis; + lineno = dothis->n->ln; Fname = dothis->n->fn; @@ -271,7 +300,7 @@ } } if (Have_claim && X && X->pid == 0 - && dothis && dothis->n + && dothis->n && lastclaim != dothis->n->ln) { lastclaim = dothis->n->ln; if (columns == 2) --- /sys/src/cmd/spin/main.c Thu Nov 17 15:27:12 2011 +++ /sys/src/cmd/spin/main.c Thu Nov 17 15:27:03 2011 @@ -12,6 +12,8 @@ #include #include "spin.h" #include "version.h" +#include +#include #include /* #include */ #include @@ -29,6 +31,7 @@ extern char *claimproc; extern void repro_src(void); extern void qhide(int); +extern char CurScope[MAXSCOPESZ]; Symbol *Fname, *oFname; @@ -40,12 +43,16 @@ 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 old_scope_rules; /* use pre 5.3.0 rules */ +int split_decl = 1, product, Strict; -int dataflow = 1, merger = 1, deadvar = 1, ccache = 1; +int merger = 1, deadvar = 1; +int ccache = 0; /* oyvind teig: 5.2.0 case caching off by default */ static int preprocessonly, SeedUsed; +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,33 +68,44 @@ 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 FILE *fd_ltl = (FILE *) 0; static char *PreArg[64]; static int PreCnt = 0; static char out1[64]; -static void explain(int); +char **trailfilename; /* new option 'k' */ + +void explain(int); + + /* to use visual C++: + #define CPP "CL -E/E" + or call spin as: "spin -PCL -E/E" + + on OS2: + #define CPP "icc -E/Pd+ -E/Q+" + or call spin as: "spin -Picc -E/Pd+ -E/Q+" + */ #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 + #if defined(PC) || defined(MAC) + #define CPP "gcc -E -x c" /* most systems have gcc or cpp */ + /* if gcc-4 is available, this setting is modified below */ + #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 #endif -#endif static char *PreProc = CPP; extern int depth; /* at least some steps were made */ @@ -114,16 +132,36 @@ void preprocess(char *a, char *b, int a_tmp) -{ char precmd[512], cmd[1024]; int i; +{ char precmd[1024], cmd[2048]; int i; +#if defined(WIN32) || defined(WIN64) + struct _stat x; +/* struct stat x; */ +#endif #ifdef PC extern int try_zpp(char *, char *); - if (PreCnt == 0 && try_zpp(a, b)) goto out; + if (PreCnt == 0 && try_zpp(a, b)) + { goto out; + } +#endif +#if defined(WIN32) || defined(WIN64) + if (strncmp(PreProc, "gcc -E -x c", strlen("gcc -E -x c")) == 0) + { if (stat("/bin/gcc-4.exe", (struct stat *)&x) == 0 /* for PCs with cygwin */ + || stat("c:/cygwin/bin/gcc-4.exe", (struct stat *)&x) == 0) + { PreProc = "gcc-4 -E -x c"; + } else if (stat("/bin/gcc-3.exe", (struct stat *)&x) == 0 + || stat("c:/cygwin/bin/gcc-3.exe", (struct stat *)&x) == 0) + { PreProc = "gcc-3 -E -x c"; + } } #endif 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)) { (void) unlink((const char *) b); @@ -137,23 +175,6 @@ 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,25 +189,30 @@ 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 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-Pxxx use xxx for preprocessing\n"); printf("\t-p print all statements\n"); printf("\t-qN suppress io for queue N in printouts\n"); @@ -194,7 +220,7 @@ 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"); @@ -205,7 +231,7 @@ } void -optimizations(char nr) +optimizations(int nr) { switch (nr) { case '1': @@ -250,31 +276,6 @@ } } -#if 0 -static int -Rename(const char *old, char *new) -{ FILE *fo, *fn; - char buf[1024]; - - if ((fo = fopen(old, "r")) == NULL) - { printf("spin: cannot open %s\n", old); - return 1; - } - if ((fn = fopen(new, "w")) == NULL) - { printf("spin: cannot create %s\n", new); - fclose(fo); - return 2; - } - while (fgets(buf, 1024, fo)) - fputs(buf, fn); - - fclose(fo); - fclose(fn); - - return 0; /* success */ -} -#endif - int main(int argc, char *argv[]) { Symbol *s; @@ -285,16 +286,15 @@ 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 */ + /* 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 'B': no_wrapup = 1; break; case 'b': no_print = 1; break; @@ -305,6 +305,7 @@ 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 +316,42 @@ 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': old_scope_rules = 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 'q': if (isdigit((int) argv[1][2])) qhide(atoi(&argv[1][2])); break; case 'r': verbose += 8; break; case 's': verbose += 16; break; case 'T': notabs = 1; break; case 't': s_trail = 1; - if (isdigit(argv[1][2])) + 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 'v': verbose += 32; break; - case 'V': printf("%s\n", Version); + case 'V': printf("%s\n", SpinVersion); alldone(0); break; case 'w': verbose += 64; break; +#if 0 + case 'x': split_decl = 0; break; /* experimental */ +#endif case 'X': xspin = notabs = 1; #ifndef PC signal(SIGPIPE, alldone); /* not posix... */ @@ -355,9 +364,10 @@ } argc--; argv++; } + if (usedopts && !analyze) printf("spin: warning -o[123] option ignored in simulations\n"); - + if (ltl_file) { char formula[4096]; add_ltl = ltl_file-2; add_ltl[1][1] = 'f'; @@ -365,41 +375,42 @@ { 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.___"); + { sprintf(out2, "%s.nvr", argv[1]); + if ((fd = fopen(out2, MFLAGS)) == NULL) + { printf("spin: cannot create tmp file %s\n", + out2); + alldone(1); + } + fprintf(fd, "#include \"%s\"\n", argv[1]); + } if (add_ltl) - { tl_out = cpyfile(argv[1], out2); - nr_errs = tl_main(2, add_ltl); /* in tl_main.c */ - fclose(tl_out); + { tl_out = fd; + nr_errs = tl_main(2, add_ltl); + fclose(fd); 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); - 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", *nvr_file); fclose(fd); preprocess(out2, out1, 1); } else - preprocess(argv[1], out1, 0); + { preprocess(argv[1], out1, 0); + } if (preprocessonly) alldone(0); @@ -409,8 +420,8 @@ alldone(1); } - if (strncmp(argv[1], "progress", 8) == 0 - || strncmp(argv[1], "accept", 6) == 0) + 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]); @@ -428,9 +439,10 @@ 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"); fflush(stdout); + alldone(1); } if (columns == 2) { extern void putprelude(void); @@ -444,7 +456,7 @@ verbose += (8+16); if (columns == 2 && limited_vis) verbose += (1+4); - Srand(T); /* defined in run.c */ + 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; @@ -454,6 +466,23 @@ 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) @@ -471,6 +500,35 @@ return 0; } +void +ltl_list(char *nm, char *fm) +{ + if (analyze || dumptab) /* when generating pan.c only */ + { 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 */ + } +} + int yywrap(void) /* dummy routine */ { @@ -481,13 +539,13 @@ non_fatal(char *s1, char *s2) { extern char yytext[]; - printf("spin: line %3d %s, Error: ", - lineno, Fname?Fname->name:"nofilename"); + printf("spin: %s:%d, Error: ", + oFname?oFname->name:"nofilename", lineno); if (s2) printf(s1, s2); else printf(s1); - if (yytext && strlen(yytext)>1) + if (strlen(yytext)>1) printf(" near '%s'", yytext); printf("\n"); nr_errs++; @@ -497,24 +555,35 @@ 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.pre"); 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) +trapwonly(Lextok *n /* , char *unused */) { extern int realread; short i = (n->sym)?n->sym->type:0; @@ -555,6 +624,7 @@ { Lextok *n = (Lextok *) emalloc(sizeof(Lextok)); static int warn_nn = 0; + n->uiid = is_inline(); /* record origin of the statement */ n->ntyp = (short) t; if (s && s->fn) { n->ln = s->ln; @@ -679,13 +749,13 @@ #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 +768,16 @@ 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; @@ -776,3 +856,5 @@ case UNLESS: fprintf(fd, "%sunless", Keyword); break; } } + + --- /sys/src/cmd/spin/mesg.c Thu Nov 17 15:27:23 2011 +++ /sys/src/cmd/spin/mesg.c Thu Nov 17 15:27:17 2011 @@ -185,9 +185,11 @@ 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--) @@ -383,7 +385,7 @@ return 1; } -void +static void channm(Lextok *n) { char lbuf[512]; @@ -394,7 +396,11 @@ 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, ""); @@ -462,7 +468,7 @@ int n; struct QH *nxt; } QH; -QH *qh; +static QH *qh; void qhide(int q) @@ -483,7 +489,7 @@ 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 +516,20 @@ } 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); @@ -572,10 +589,15 @@ 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 +631,10 @@ } } - 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) return; if (n->sym && n->sym->type == CHAN) @@ -627,6 +652,120 @@ nochan_manip(p, n->rgt, 1); } +typedef struct BaseName { + char *str; + int cnt; + struct BaseName *nxt; +} BaseName; +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; @@ -641,4 +780,6 @@ || (strlen(sp) == strlen("_p") && strcmp(sp, "_p") == 0)) { fatal("attempt to assign value to system variable %s", sp); } + + no_nested_array_refs(n); } --- /sys/src/cmd/spin/mkfile Thu Nov 17 15:27:30 2011 +++ /sys/src/cmd/spin/mkfile Thu Nov 17 15:27:27 2011 @@ -14,6 +14,7 @@ pangen4.$O\ pangen5.$O\ pangen6.$O\ + pangen7.$O\ pc_zpp.$O\ ps_msc.$O\ reprosrc.$O\ @@ -53,4 +54,4 @@ main.$O pangen2.$O ps_msc.$O: version.h pangen1.$O: pangen1.h pangen3.h -pangen2.$O: pangen2.h pangen4.h pangen5.h +pangen2.$O: pangen2.h pangen4.h pangen5.h pangen6.h --- /sys/src/cmd/spin/pangen1.c Thu Nov 17 15:27:47 2011 +++ /sys/src/cmd/spin/pangen1.c Thu Nov 17 15:27:37 2011 @@ -8,11 +8,14 @@ /* Software written by Gerard J. Holzmann. For tool documentation see: */ /* http://spinroot.com/ */ /* Send all bug-reports and/or questions to: bugs@spinroot.com */ +/* (c) 2007: small additions for V5.0 to support multi-core verifications */ #include "spin.h" #include "y.tab.h" #include "pangen1.h" #include "pangen3.h" +#include "pangen6.h" +#include extern FILE *tc, *th, *tt; extern Label *labtab; @@ -20,9 +23,10 @@ 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 Queue *ltab[]; int Npars=0, u_sync=0, u_async=0, hastrack = 1; short has_io = 0; @@ -36,9 +40,10 @@ 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 @@ -48,6 +53,21 @@ reverse_names(p->nxt); fprintf(th, " \"%s\",\n", p->n->name); } +static void +reverse_types(ProcList *p) +{ + if (!p) return; + reverse_types(p->nxt); + fprintf(th, " %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 genheader(void) @@ -57,9 +77,19 @@ { 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"); putunames(th); @@ -67,6 +97,11 @@ 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"); @@ -74,18 +109,86 @@ fprintf(th, " \":np_:\",\n"); fprintf(th, "};\n\n"); + fprintf(th, "enum btypes { NONE=%d, N_CLAIM=%d,", NONE, N_CLAIM); + fprintf(th, " I_PROC=%d, A_PROC=%d,", I_PROC, A_PROC); + fprintf(th, " P_PROC=%d, E_TRACE=%d, N_TRACE=%d };\n", + P_PROC, E_TRACE, N_TRACE); + fprintf(th, "int Btypes[] = {\n"); + reverse_types(rdy); + fprintf(th, " 0 /* :np_: */\n"); + fprintf(th, "};\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 <= 255) /* in stdint.h = UCHAR_MAX from limits.h */ + { fprintf(th, " uchar c_cur[NCLAIMS]; /* claim-states */\n"); + } else if (i <= 65535) /* 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(th, "uchar spin_c_typ[NCLAIMS]; /* claim-types */\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, "\n#define Pclaim P0\n"); + fprintf(th, "#ifndef NCLAIMS\n"); + fprintf(th, " #define NCLAIMS 1\n"); + fprintf(th, "#endif\n"); + fprintf(th, "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); } @@ -96,7 +199,13 @@ 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,6 +214,23 @@ #endif fprintf(th, ";\n\n"); + 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, "TRIX_v6 *freebodies;\n"); + fprintf(th, "TRIX_v6 *processes[MAXPROC+1];\n"); + fprintf(th, "TRIX_v6 *channels[MAXQ+1]; \n"); + fprintf(th, "long _p_count[MAXPROC];\n"); + fprintf(th, "long _c_count[MAXPROC];\n"); + fprintf(th, "#endif\n\n"); + fprintf(th, "#define HAS_TRACK %d\n", hastrack); if (separate != 2) @@ -114,16 +240,52 @@ void genaddproc(void) { ProcList *p; - int i = 0; + int i = 0, j; + + if (separate == 2) goto shortcut; + + fprintf(tc, "\n#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 */ + fprintf(tc, "void\nre_mark_all(int whichway)\n"); + fprintf(tc, "{ int j;\n"); + fprintf(tc, " #ifdef V_TRIX\n"); + fprintf(tc, " printf(\"%%d: re_mark_all channels %%d\\n\", depth, whichway);\n"); + fprintf(tc, " #endif\n"); + fprintf(tc, " #ifndef BFS\n"); + fprintf(tc, " for (j = 0; j < now._nr_qs; j++)\n"); + fprintf(tc, " channels[j]->modified = 1; /* channel index moved */\n"); + fprintf(tc, " #endif\n"); + fprintf(tc, " #ifndef TRIX_ORIG\n"); + fprintf(tc, " if (whichway > 0)\n"); + fprintf(tc, " { for (j = now._nr_pr + now._nr_qs - 1; j >= now._nr_pr; j--)\n"); + fprintf(tc, " now._ids_[j] = now._ids_[j-1];\n"); + fprintf(tc, " } else\n"); + fprintf(tc, " { for (j = now._nr_pr; j < now._nr_pr + now._nr_qs; j++)\n"); + fprintf(tc, " now._ids_[j] = now._ids_[j+1];\n"); + fprintf(tc, " }\n"); + fprintf(tc, " #endif\n"); + fprintf(tc, "}\n"); - if (separate ==2) goto shortcut; + fprintf(tc, "#endif\n\n"); - fprintf(tc, "int\naddproc(int n"); - for (i = 0; i < Npars; i++) + fprintf(tc, "int\naddproc(int calling_pid, 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 +294,9 @@ 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; @@ -167,13 +332,18 @@ 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 */ + } } } 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 */ + } } break; case 0: ntimes(tc, 0, 1, Code0); @@ -186,44 +356,53 @@ 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, 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"); + ntimes(tc, 1, u_sync+u_async+1, R3); /* because 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"); + + /* after the value of Maxbody has settled */ 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,13 +427,13 @@ 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); @@ -272,8 +451,7 @@ 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 @@ -305,7 +483,7 @@ 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 +516,7 @@ { 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 +539,12 @@ } } -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 +568,8 @@ 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 +588,7 @@ k++; break; } - if (strcmp(s, ":never:") == 0) + if (b == N_CLAIM) { printf("error: %s defines local %s\n", s, sp->name); nr_errs++; @@ -426,7 +605,7 @@ if (!qtab) { fprintf(fd, "void\nc_chandump(int unused) "); - fprintf(fd, "{ unused = unused++; /* avoid complaints */ }\n"); + fprintf(fd, "{ unused++; /* avoid complaints */ }\n"); return; } @@ -465,9 +644,19 @@ 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?sp->name:""; + if (!old_scope_rules) + { while (*ptr == '_' || isdigit((int)*ptr)) + { ptr++; + } } + switch (sp->type) { case STRUCT: /* c_struct(fd, pref, sp); */ @@ -480,30 +669,29 @@ case SHORT: case INT: case UNSIGNED: sputtype(buf, sp->type); - if (sp->nel == 1) + if (sp->nel == 1 && sp->isarray == 0) { fprintf(fd, "\tprintf(\"\t%s %s:\t%%d\\n\", %s%s);\n", - buf, sp->name, pref, sp->name); + 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 +706,7 @@ { 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 +727,7 @@ 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 @@ -583,8 +767,6 @@ 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 +815,9 @@ 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; @@ -665,15 +848,25 @@ 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 +875,16 @@ } 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) @@ -722,42 +918,31 @@ 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"); @@ -765,14 +950,14 @@ fprintf(th, " unsigned _p : %d; /* state */\n", blog(m0)); LstSet = ZS; nBits = 8 + blog(m1) + blog(m0); - k = dolocal(tc, "", PUTV, i, s); /* includes pars */ + k = dolocal(tc, "", PUTV, i, s, 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 + 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); @@ -813,6 +998,7 @@ fprintf(th, "#define _NP_ %d\n", i); /* if (separate == 2) fprintf(th, "extern "); */ fprintf(th, "uchar reached%d[3]; /* np_ */\n", i); + fprintf(th, "uchar *loopstate%d; /* np_ */\n", i); fprintf(th, "#define nstates%d 3 /* np_ */\n", i); fprintf(th, "#define endstate%d 2 /* np_ */\n\n", i); @@ -831,6 +1017,48 @@ } 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; Element *e = P->s->frst; @@ -839,29 +1067,30 @@ 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); 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, "\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 +1108,7 @@ 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 +1127,10 @@ 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"); } @@ -939,7 +1168,7 @@ int cnt=0; /* a precaution against loops */ if (e) - for (cnt = 0; cnt < 200 && e->n; cnt++) + for ( ; cnt < 200 && e->n; cnt++) { if (e->seqno == stopat) break; @@ -992,7 +1221,7 @@ 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,7 +1260,7 @@ fatal("variable %s undeclared", sp->name); } - if (sp->nel != 1) + if (sp->nel > 1 || sp->isarray) fprintf(th, "[%d]", sp->nel); fprintf(th, ";\n"); } @@ -1124,6 +1353,22 @@ 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 +1404,7 @@ 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 +1447,12 @@ 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); @@ -1266,9 +1517,10 @@ fprintf(th, "void qsend(int, int"); for (j = 0; j < Mpars; j++) fprintf(th, ", int"); - fprintf(th, ");\n"); + fprintf(th, ", int);\n"); - fprintf(th, "#define Addproc(x) addproc(x"); + fprintf(th, "#define Addproc(x) addproc(256, x"); + /* 256 is param outside the range of valid pids */ for (j = 0; j < Npars; j++) fprintf(th, ", 0"); fprintf(th, ")\n"); --- /sys/src/cmd/spin/pangen1.h Thu Nov 17 15:28:39 2011 +++ /sys/src/cmd/spin/pangen1.h Thu Nov 17 15:28:08 2011 @@ -1,6 +1,6 @@ /***** spin: pangen1.h *****/ -/* Copyright (c) 1989-2005 by Lucent Technologies, Bell Laboratories. */ +/* 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 */ @@ -8,13 +8,42 @@ /* Software written by Gerard J. Holzmann. For tool documentation see: */ /* http://spinroot.com/ */ /* Send all bug-reports and/or questions to: bugs@spinroot.com */ +/* (c) 2007-2011: additions, enhancements, and bugfixes GJH */ static 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", + " iniglobals(258); /* arg outside range of pids */", "#if defined(VERI) && !defined(NOREDUCE) && !defined(NP)", " 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,33 +53,49 @@ "#endif", " UnBlock; /* disable rendez-vous */", "#ifdef BITSTATE", -#ifndef POWOW " if (udmem)", " { udmem *= 1024L*1024L;", + " #if NCORE>1", + " if (!readtrail)", + " { void init_SS(unsigned long);", + " init_SS((unsigned long) udmem);", + " } else", + " #endif", " SS = (uchar *) emalloc(udmem);", " bstore = bstore_mod;", " } else", -#endif - " SS = (uchar *) emalloc(1L<<(ssize-3));", - "#else", + " #if NCORE>1", + " { void init_SS(unsigned long);", + " init_SS(ONE_L<<(ssize-3));", + " }", + " #else", + " SS = (uchar *) emalloc(ONE_L<<(ssize-3));", + " #endif", + "#else", /* if not BITSTATE */ " hinit();", "#endif", "#if defined(FULLSTACK) && defined(BITSTATE)", " 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); /* pid = 0 */", + " #if NCLAIMS>1", + " if (claimname != NULL)", + " { whichclaim = find_claim(claimname);", + " select_claim(whichclaim);", + " }", + " #endif", "#endif", " active_procs(); /* started after never */", "#ifdef EVENT_TRACE", @@ -70,11 +115,17 @@ " { 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 *));", "#endif", @@ -90,6 +141,68 @@ "int provided(int, uchar, int, Trans *);", "#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", + "", + "void e_critical(int);", + "void x_critical(int);", + "", + "#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", + "int", + "cpu_printf(const char *fmt, ...)", + "{ va_list args;", + " va_start(args, fmt);", + " vprintf(fmt, args);", + " va_end(args);", + " return 1;", + "}", + "#endif", + #ifndef PRINTF "int", "Printf(const char *fmt, ...)", @@ -172,44 +285,92 @@ "#endif", "#endif", + "#if NCORE>1", + "extern void cleanup_shm(int);", + "volatile unsigned int *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", "void", "pan_exit(int val)", - "{ if (signoff) printf(\"--end of output--\\n\");", + "{ void stop_timer(void);", + " 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", + " if (val == 2)", + " { val = 0;", + " } else", + " { stop_timer();", + " }", + "", + "#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 +384,6 @@ "", " 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 +393,17 @@ " 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 +414,15 @@ "", " 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 +441,8 @@ " 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 +466,100 @@ "findtrail(void)", "{ FILE *fd;", " char fnm[512], *q;", - " char MyFile[512];", - "", - " strcpy(MyFile, TrailFile);", /* avoid problem with non-writable strings */ - "", + " char MyFile[512];", /* avoid using a non-writable string */ + " char MySuffix[16];", + " int try_core;", + " int candidate_files;", + "", + " 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,15 +568,22 @@ " 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;", "}", "", @@ -352,22 +609,23 @@ " 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);", @@ -391,16 +649,24 @@ " 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, procname[z->_t]);", + + " 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,8 +679,7 @@ " }", " 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)", @@ -429,7 +694,8 @@ " depth, II, procname[z->_t]);", " for (i = 0; src_all[i].src; i++)", " if (src_all[i].tp == (int) z->_t)", - " { printf(\" line %%3d \\\"pan_in\\\" \",", + " { printf(\" %%s:%%d \",", + " find_source((int) z->_t, (int) z->_p),", " src_all[i].src[z->_p]);", " break;", " }", @@ -439,12 +705,13 @@ " depth, II, procname[z->_t]);", " for (i = 0; src_all[i].src; i++)", " if (src_all[i].tp == (int) z->_t)", - " { printf(\" line %%3d \\\"pan_in\\\" \",", + " { 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 +729,36 @@ " }", " return -1;", "}", - "#ifdef VERI", - "void check_claim(int);", + "", + "#if !defined(HASH64) && !defined(HASH32)", + " #if WS>4", + " #define HASH64", + " #else", + " #define HASH32", + " #endif", + "#endif", + "#if defined(HASH32) && defined(SAFETY) && !defined(SFH) && !defined(SPACE)", + " #define SFH", + "#endif", + "#if defined(SFH) && (defined(BITSTATE) || defined(COLLAPSE) || defined(HC) || defined(HASH64) || defined(MA))", + " #undef SFH", /* need 2 hash fcts, for which Jenkins is best */ + "#endif", /* or a 64 bit hash, which we dont have for SFH */ + /* for MA, it would slow down the search to use a larger sv then possible */ + "#if defined(SFH) && !defined(NOCOMP)", + " #define NOCOMP /* go for speed */", + "#endif", + "#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;", + " x = K1; y = j3;", /* was K2 before 5.1.1 */ " for (;;)", " { if (!(SS[x%%udmem]&(1< 0)", - " sprintf(fnm, \"%%s%%d.%%s\",", + " { sprintf(fnm, \"%%s%%d.%%s\",", " MyFile, Nr_Trails-1, tprefix);", - " else", + " } 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,25 +867,65 @@ " 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", + " 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;", + "#endif", + "#ifndef BFS", + " processes[i]->modified = 1; /* re-populate */", + "#endif", + " }", + " 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 */ + "#define Q_PROVISO", + " #ifndef INLINE_REV", + " #define INLINE_REV", + " #endif", "", "typedef struct SV_Hold {", " State *sv;", @@ -605,13 +938,10 @@ " int sz;", /* vsize */ " int nrpr;", " int nrqs;", - "#if VECTORSZ>32000", - " int *po;", - "#else", - " short *po;", + "#ifndef TRIX", + " char *po, *qo;", + " char *ps, *qs;", "#endif", - " int *qo;", - " uchar *ps, *qs;", " struct EV_Hold *nxt;", "} EV_Hold;", "", @@ -623,6 +953,9 @@ " struct H_el *lstate;", "#endif", " short boq;", + "#ifdef VERBOSE", + " unsigned long nr;", + "#endif", " struct BFS_Trail *nxt;", "} BFS_Trail;", "", @@ -630,9 +963,38 @@ "", "SV_Hold *svhold, *svfree;", "", + "#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)", + " #else", + " #define RFLAGS (O_RDONLY)", + " #define WFLAGS (O_CREAT|O_WRONLY|O_TRUNC)", + " #endif", + + "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);", "", + "void", + "select_claim(int x) /* ignored in BFS mode */", + "{ if (verbose)", + " { printf(\"select %%d (ignored)\\n\", x);", + " }", + "}", + "", "SV_Hold *", "getsv(int n)", "{ SV_Hold *h = (SV_Hold *) 0, *oh;", @@ -657,8 +1019,34 @@ " if (!h)", " { 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;", "}", "", @@ -672,15 +1060,19 @@ " && (memcmp((char *) Mask, (char *) h->sv, n) == 0)", " && (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))", " break;", " if (!h)", " { h = (EV_Hold *) emalloc(sizeof(EV_Hold));", @@ -690,28 +1082,30 @@ "", " h->sv = (char *) emalloc(n * sizeof(char));", " memcpy((char *) h->sv, (char *) Mask, n);", - "", + "#ifndef TRIX", " 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", + " { 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", + " #else", + " h->po = (char *) emalloc(now._nr_pr * sizeof(short));", " memcpy((char *) h->po, (char *) proc_offset, now._nr_pr * sizeof(short));", - "#endif", - " memcpy((char *) h->ps, (char *) proc_skip, now._nr_pr * sizeof(uchar));", + " #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", + " { 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", + " #else", + " h->qo = (char *) emalloc(now._nr_qs * sizeof(short));", " memcpy((char *) h->qo, (char *) q_offset, now._nr_qs * sizeof(short));", - "#endif", - " memcpy((char *) h->qs, (char *) q_skip, now._nr_qs * sizeof(uchar));", + " #endif", " }", - "", + "#endif", " h->nxt = kept;", " kept = h;", " }", @@ -724,9 +1118,9 @@ "", " oh = (SV_Hold *) 0;", " for (h = svfree; h; oh = h, h = h->nxt)", - " if (h->sz >= p->sz)", + " { if (h->sz >= p->sz)", " break;", - "", + " }", " if (!oh)", " { p->nxt = svfree;", " svfree = p;", @@ -748,6 +1142,8 @@ " { t = (BFS_Trail *) emalloc(sizeof(BFS_Trail));", " }", " 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;", "}", "", @@ -760,8 +1156,10 @@ " 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;", @@ -772,8 +1170,11 @@ " { bfs_bot->nxt = t;", " bfs_bot = t;", " }", + "#ifdef VERBOSE", + " t->nr = nstates;", + "#endif", "#ifdef CHECK", - " printf(\"PUSH %%u (%%d)\\n\", t->frame, d);", + " printf(\"PUSH %%u (depth %%d, nr %%d)\\n\", t->frame, d, t->nr);", "#endif", "}", "", @@ -782,45 +1183,80 @@ "{ BFS_Trail *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;", + " { bfs_bot = (BFS_Trail *) 0;", + " }", "#if defined(Q_PROVISO) && !defined(BITSTATE) && !defined(NOREDUCE)", - " if (t->lstate) t->lstate->tagged = 0;", + " if (t->lstate)", + " { t->lstate->tagged = 0;", + " }", "#endif", - "", " t->nxt = bfs_free;", " bfs_free = t;", "", " vsize = t->onow->sz;", " boq = t->boq;", - "", - " memcpy((uchar *) &now, (uchar *) t->onow->sv, vsize);", + "#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);", + " }", " memcpy((uchar *) Mask, (uchar *) t->omask->sv, vsize);", - + "#ifdef TRIX", + " re_populate();", + "#else", " if (now._nr_pr > 0)", - "#if VECTORSZ>32000", + " #if VECTORSZ>32000", " { memcpy((char *)proc_offset, (char *)t->omask->po, now._nr_pr * sizeof(int));", - "#else", + " #else", " { memcpy((char *)proc_offset, (char *)t->omask->po, now._nr_pr * sizeof(short));", - "#endif", + " #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 */", + "#endif", + "#ifdef BFS_DISK", + " if (t->onow->sv != (State *) 0)", + "#endif", + " { freesv(t->onow); /* omask not freed */", + " }", "#ifdef CHECK", - " printf(\"POP %%u (%%d)\\n\", t->frame, t->frame->o_tt);", + " printf(\"POP %%u (depth %%d, nr %%d)\\n\", t->frame, t->frame->o_tt, t->nr);", "#endif", " return t->frame;", "}", @@ -835,71 +1271,84 @@ "", " 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 */ "", - "#ifdef BITSTATE", + "#if defined(BITSTATE)", " if (!bstore((char *)&now, vsize))", - "#else", - "#ifdef MA", + "#elif defined(MA)", " if (!gstore((char *)&now, vsize, 0))", - "#else", + "#else", " if (!hstore((char *)&now, vsize))", - "#endif", "#endif", - " { nstates++;", + " { static long sdone = (long) 0; long ndone;", + " nstates++;", "#ifndef NOREDUCE", - " trpt->tau |= 64;", /* succ definitely outside stack */ + " trpt->tau |= 64;", /* bfs: succ definitely outside stack */ + "#endif", + " ndone = (unsigned long) (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++;", @@ -914,17 +1363,20 @@ " { truncs++;", "#if !defined(NOREDUCE) && defined(FULLSTACK) && defined(Q_PROVISO)", - "#if !defined(QLIST) && !defined(BITSTATE)", - " if (Lstate && Lstate->tagged) trpt->tau |= 64;", - "#else", + " #if !defined(BITSTATE)", + " if (Lstate && Lstate->tagged)", + " { trpt->tau |= 64;", + " }", + " #else", " if (trpt->tau&32)", " { BFS_Trail *tprov;", " for (tprov = bfs_trail; tprov; tprov = tprov->nxt)", - " if (!memcmp((uchar *)&now, (uchar *)tprov->onow->sv, vsize))", + " 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", " }", "#ifdef VERI", @@ -976,19 +1428,19 @@ " { 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", " 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 */", " }", @@ -998,13 +1450,7 @@ " 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;", @@ -1023,16 +1469,15 @@ " printf(\"error: max search depth too small\\n\");", " }", " if (bounded)", - " uerror(\"depth limit reached\");", + " { uerror(\"depth limit reached\");", + " }", " continue;", " }", - -/* PO */ "#ifndef NOREDUCE", " if (boq == -1 && !(trpt->tau&8) && nps == 0)", " for (II = now._nr_pr-1; II >= BASE; II -= 1)", " {", - "Pickup: this = pptr(II);", + "Pickup: this = pptr(II);", " tt = (int) ((P0 *)this)->_p;", " ot = (uchar) ((P0 *)this)->_t;", " if (trans[ot][tt]->atom & 8)", /* safe */ @@ -1045,15 +1490,14 @@ " }", " 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,21 +1510,25 @@ " _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", " /* no rendezvous with same proc */", - " if (boq != -1 && trpt->pr == II) continue;", + " if (boq != -1 && trpt->pr == II)", + " { continue;", + " }", "#endif", " ntrpt->pr = (uchar) II;", " ntrpt->st = tt; ", - " trpt->o_pm &= ~1; /* no move yet */", + " 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;", + " if (!provided(II, ot, tt, t))", + " { continue;", + " }", "#endif", "#ifdef HAS_UNLESS", " E_state = 0;", @@ -1101,34 +1549,36 @@ "", " trpt->o_pm |= 1; /* we moved */", " (trpt+1)->o_m = _m; /* for unsend */", - "#ifdef PEG", + "#ifdef PEG", " peg[t->forw]++;", - "#endif", + "#endif", "#ifdef CHECK", - " printf(\"%%3d: proc %%d exec %%d, \",", + " 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", " 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", "#endif", - " if (t->st > 0) ((P0 *)this)->_p = t->st;", + " if (t->st > 0)", + " { ((P0 *)this)->_p = t->st;", + " }", "", " /* ptr to pred: */ ntrpt->ostate = (struct H_el *) otrpt;", " ntrpt->st = tt;", @@ -1136,17 +1586,19 @@ " ntrpt->tau = 8; /* record for next move */", " else", " ntrpt->tau = 0;", - "", " store_state(ntrpt, (boq != -1 || (t->atom&2)), oboq);", "#ifdef EVENT_TRACE", " now._event = trpt->o_event;", "#endif", - "", " /* undo move and continue */", " trpt++; /* this is where ovals and ipt are set */", " do_reverse(t, II, _m); /* restore now. */", " trpt--;", "#ifdef CHECK", + " #if NCORE>1", + " enter_critical(GLOBAL_LOCK); /* verbose mode */", + " printf(\"cpu%%d: \", core_id);", + " #endif", " printf(\"%%3d: proc %%d \", depth, II);", " printf(\"reverses %%d, %%d to %%d,\",", " t->forw, tt, t->st);", @@ -1154,43 +1606,48 @@ " t->tp, now._a_t, A_depth);", " printf(\"tau=%%d,%%d]\\n\",", " trpt->tau, (trpt-1)->tau);", + " #if NCORE>1", + " leave_critical(GLOBAL_LOCK);", + " #endif", "#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;", + " { continue;", + " }", "#ifdef DEBUG", - " printf(\"%%3d: no move [II=%%d, tau=%%d, boq=%%d, _nr_pr=%%d]\\n\",", + " printf(\"%%3ld: no move [II=%%d, tau=%%d, boq=%%d, _nr_pr=%%d]\\n\",", " depth, II, trpt->tau, boq, now._nr_pr);", "#endif", " if (boq != -1)", " { failedrv++;", - " x = (Trail *) trpt->ostate; /* pre-rv state */", - " if (!x) continue; /* root state */", + " 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]);", + " this = pptr(otrpt->pr);", "#ifdef VERBOSE", " printf(\"\\treset state of %%d from %%d to %%d\\n\",", " otrpt->pr, ((P0 *)this)->_p, otrpt->st);", @@ -1205,14 +1662,16 @@ "#endif", " }", "#ifdef VERBOSE", - " else printf(\"failed rv, tau at parent: %%d\\n\", x->tau);", + " 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\",", + " printf(\"%%3ld: atomic step proc %%d blocks\\n\",", " depth, II+1);", "#endif", " goto Repeat;", @@ -1227,7 +1686,8 @@ " }", "#ifndef VERI", " if (!noends && !a_cycles && !endstate())", - " uerror(\"invalid end state\");", + " { uerror(\"invalid end state\");", + " }", "#endif", " } }", "}", @@ -1258,12 +1718,12 @@ "", " 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);", + " (void) write(fd, snap, strlen(snap));", "#endif", "#ifdef MERGED", " sprintf(snap, \"-4:-4:-4\\n\");", - " write(fd, snap, strlen(snap));", + " (void) write(fd, snap, strlen(snap));", "#endif", " trcnt = 1;", " putter(trpt, fd);", @@ -1277,15 +1737,129 @@ " } }", " close(fd);", " if (errors >= upto && upto != 0)", - " {", - " wrapup();", + " { wrapup();", " }", "}", "#endif", /* BFS */ 0, }; -static char *Code2c[] = { +static char *Code2d[] = { + "clock_t start_time;", + "#if NCORE>1", + "clock_t crash_stamp;", + "#endif", + "#if !defined(WIN32) && !defined(WIN64)", + "struct tms start_tm;", + "#endif", + "", + "void", + "start_timer(void)", + "{", + "#if defined(WIN32) || defined(WIN64)", + " start_time = clock();", + "#else", + " start_time = times(&start_tm);", + "#endif", + "}", + "", + "void", + "stop_timer(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 (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", + " 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));", + " } }", + "#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", + "", "void", "do_the_search(void)", "{ int i;", @@ -1340,12 +1914,19 @@ " { 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,6 +1935,7 @@ "#ifdef HAS_CODE", " if (readtrail) getrail(); /* no return */", "#endif", + " start_timer();", "#ifdef BFS", " bfs();", "#else", @@ -1361,11 +1943,17 @@ " /* initial state of tracked & unmatched objects */", " c_stack((uchar *) &(svtack->c_stack[0]));", "#endif", - "#ifdef RANDOMIZE", - " srand(123);", - "#endif", + + "#if defined(P_RAND) || defined(T_RAND)", + " srand(s_rand);", + "#endif", + + "#if NCORE>1", + " mem_get();", + "#else", " new_state(); /* start 1st DFS */", "#endif", + "#endif", "}", "#ifdef INLINE_REV", @@ -1392,7 +1980,7 @@ "#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", "#define continue return 0", @@ -1403,12 +1991,11 @@ "#include FORWARD_MOVES", "P999:", "#ifdef EVENT_TRACE", - " if (ot == EVENT_TRACE) boq = oboq;", + " if (II == -EVENT_TRACE) boq = oboq;", "#endif", " return _m;", "#undef continue", "}", - "#ifdef EVENT_TRACE", "void", "require(char tp, int qid)", @@ -1417,7 +2004,7 @@ "", " 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", @@ -1446,7 +2033,7 @@ " }", "#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;", @@ -1470,7 +2057,6 @@ "#endif", "}", "#endif", - "int", "enabled(int iam, int pid)", "{ Trans *t; uchar *othis = this;", @@ -1497,20 +2083,56 @@ "}", "#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);", + "{", + "#if NCORE>1", + " enter_critical(GLOBAL_LOCK); /* 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= %%7d \", nr_states);", "#endif", - " printf(\"Memory= %%-6.3f\\n\", memcnt/1000000.);", + " printf(\"Memory= %%9.3f\\t\", memcnt/1048576.);", + " snap_time();", " fflush(stdout);", + "#if NCORE>1", + " leave_critical(GLOBAL_LOCK);", + "#endif", "}", - "#ifdef SC", "void", "stack2disk(void)", @@ -1552,46 +2174,144 @@ "#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);", - "}", - "int qs_empty(void);", + "}\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", + "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", + "", + "#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]);", + " }", + " ((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\");", + " } }", + "}", + "#else", + "void", + "select_claim(int n)", + "{ if (n != 0) uerror(\"non-existing claim\");", + "}", + "#endif", + "", + "#ifdef 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 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 ALL_P (II = From; II >= To; II--)", + "#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 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();", @@ -1608,23 +2328,54 @@ "#if defined(FULLSTACK) && defined(MA)", " trpt->proviso = 0;", "#endif", - " if (depth >= maxdepth)", - " { truncs++;", + "#ifdef NSUCC", + " trpt->n_succ = 0;", + "#endif", + "#if NCORE>1", + " if (mem_hand_off())", + " {", "#if SYNC", - " (trpt+1)->o_n = 1; /* not a deadlock */", + " (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", - " if (!warned)", + " 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))", @@ -1649,6 +2400,11 @@ "#else", " uerror(\"acceptance cycle\");", "#endif", + "#if NCORE>1 && defined(FULL_TRAIL)", + " if (upto > 0)", + " { Pop_Stack_Tree();", + " }", + "#endif", " goto Up;", " }", "#ifdef CHECK", @@ -1658,20 +2414,61 @@ "#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 */ + " #if defined(BCS) && defined(STORE_CTX)", + " { int xj;", + " for (xj = trpt->sched_limit; xj <= sched_max; xj++)", + " { now._ctx = xj;", + " II = bstore((char *)&now, vsize);", + " trpt->j6 = j1_spin; trpt->j7 = j2;", + " JJ = LL[j1_spin] && LL[j2];", + " if (II != 0) { break; }", + " }", + " now._ctx = 0; /* just in case */", + " }", + " #else", " II = bstore((char *)&now, vsize);", - " trpt->j6 = j1; trpt->j7 = j2;", - " JJ = LL[j1] && LL[j2];", + " trpt->j6 = j1_spin; trpt->j7 = j2;", + " JJ = LL[j1_spin] && LL[j2];", + " #endif", "#else", - "#ifdef FULLSTACK", - " JJ = onstack_now();", /* sets j1 */ - "#else", - "#ifndef NOREDUCE", - " JJ = II; /* worstcase guess for p.o. */", - "#endif", - "#endif", + " #ifdef FULLSTACK", /* bstore 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 = bstore((char *)&now, vsize);", /* sets j1-j4 */ + " if (II != 0) { break; }", + " }", + " now._ctx = 0;", + " }", + " #else", + " JJ = onstack_now();", /* mangles j1 */ " II = bstore((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 = bstore((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 = bstore((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", @@ -1683,41 +2480,55 @@ "#endif", "#else", " II = hstore((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)", + "#if NCORE==1 || defined (SEP_STATE)", /* or else we don't know which stack its on */ " 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 0", + " if (!fairness || ((now._a_t&1) && now._cnt[1] == 1)) /* 5.1.4 */", + "#else", + " if (a_cycles && !fairness) /* 5.1.6 -- example by Hirofumi Watanabe */", + "#endif", + " #endif", + " {", + " 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))", @@ -1741,37 +2552,103 @@ "#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 = (unsigned long) (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((char *) &now, vsize); /* set K1 */", + " HASH_NR = oh;", + " }", + " if (write(svfd, (uchar *) &K1, sizeof(unsigned long)) != sizeof(unsigned long))", + " #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", @@ -1782,6 +2659,7 @@ " }", "#endif", " }", + "#if defined(FULLSTACK) || defined(CNTRSTACK)", " onstack_put();", "#ifdef DEBUG2", @@ -1793,10 +2671,13 @@ " printf(\"%%d: putting\\n\", depth);", "#endif", "#endif", + "#else", + " #if NCORE>1", + " trpt->ostate = Lstate;", + " #endif", "#endif", " } }", - " if (depth > mreached)", " mreached = depth;", "#ifdef VERI", @@ -1810,11 +2691,13 @@ "#ifdef VERI", " if (now._nr_pr == 0) /* claim terminated */", " uerror(\"end state in claim reached\");", - " check_claim(((P0 *)pptr(0))->_p);", + "", + " 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", " if ((now._a_t&2) /* A-bit set */", " && now._cnt[now._a_t&1] == 1)", @@ -1827,7 +2710,6 @@ "#endif", " }", "#endif", - " II = 0; /* never */", " goto Veri0;", " }", @@ -1835,14 +2717,23 @@ "#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 +2743,56 @@ "#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;", + "#endif", /* SAFETY */ + " /* attempt Partial Order Reduction as preselect moves */", + "#ifdef BCS", + " if (trpt->sched_limit < sched_max)", /* po only if we can switch */ + "#endif", + " { for ALL_P", + " {", + "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++;", + " }", + "SelectIt: From = To = II; /* preselect process */", "#ifdef NIBIS", - " t->om = 0;", + " t->om = 0;", "#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;", - " }", - " }", + " trpt->tau |= 32; /* preselect marker */", + "#ifdef DEBUG", + " printf(\"%%3ld: proc %%d PreSelected (tau=%%d)\\n\", ", + " depth, II, trpt->tau);", + "#endif", + " goto Again;", + " } } }", " 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 +2801,133 @@ " && !(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", + " #ifdef REVERSE", + " trpt->p_left = 1 + (To - From);", + " #else", + " trpt->p_left = 1 + (From - To);", + " #endif", + " 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", + + " /* Main Expansion Loop over Processes */", + " for ALL_P", " {", + "#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", + " continue;", + " }", + " 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;", "#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", + " continue;", /* 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", + " continue;", + " }", + " 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", + " continue; /* enforce bound */", + " } }", + "#endif", + "#ifdef VERI", "Veri0:", "#endif", @@ -1990,7 +2971,7 @@ " 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", @@ -2007,27 +2988,31 @@ " (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)", - " { t = trans[ot][tt];", - "#ifdef VERBOSE", - " printf(\"randomizer: suppressed, saw else\\n\");", + " { 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 or escape\\n\");", + " #endif", " } else", " { 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,6 +3030,9 @@ " 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", @@ -2052,42 +3040,71 @@ "#else", " 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 +3160,10 @@ " trpt->o_ot = ot; trpt->o_tt = tt;", " trpt->o_To = To; trpt->o_m = _m;", " trpt->tau = 0;", -"#ifdef RANDOMIZE", + + "#ifdef T_RAND", " trpt->oo_i = ooi;", -"#endif", + "#endif", " if (boq != -1 || (t->atom&2))", " { trpt->tau |= 8;", "#ifdef VERI", @@ -2171,30 +3189,76 @@ " 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 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 CHECK", - " printf(\"%%d: Up - %%s\\n\", depth,", - " (trpt->tau&4)?\"claim\":\"program\");", + " cpu_printf(\"%%d: Up - %%s\\n\", depth,", + " (trpt->tau&4)?\"claim\":\"program\");", "#endif", - "#ifdef MA", - " if (depth <= 0) return;", - " /* e.g., if first state is old, after a restart */", + "#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 %%d: %%d\\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 +3267,7 @@ " _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;", " }", @@ -2226,17 +3290,13 @@ "#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 T_RAND", " ooi = trpt->oo_i;", -"#endif", + "#endif", "#ifdef INLINE_REV", " _m = do_reverse(t, II, _m);", "#else", @@ -2245,42 +3305,42 @@ "#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=%%d,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 +3351,18 @@ " ((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 +3372,12 @@ " { 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,7 +3386,7 @@ " { 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", @@ -2335,23 +3395,66 @@ "#endif", " } /* all processes */", + "#ifdef NSUCC", + " tally_succ(trpt->n_succ);", + "#endif", + + "#ifdef P_RAND", + " if (trpt->p_left > 0)", + " { 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", + "#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 */ @@ -2382,14 +3485,14 @@ "#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 +3500,7 @@ " 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 +3509,7 @@ " 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,15 +3517,22 @@ "#ifndef NOREDUCE", "#ifdef SAFETY", + " #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))", - " { 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", + " #endif", + " { From = FROM_P; To = UPTO_P;", + " #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 */", + + " if (MORE_P) /* II already decremented */", " goto Resume;", " else", " goto Again;", @@ -2430,19 +3540,18 @@ "#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 +3575,26 @@ " 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 */", + " if (MORE_P) /* II already decremented */", " goto Resume;", " else", " goto Again;", " } }", - "/* #endif */", "#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: */", @@ -2497,15 +3605,14 @@ "#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 */", @@ -2525,7 +3632,7 @@ " { trpt->tau |= 1;", " trpt->tau &= ~2;", "#ifdef DEBUG", - " printf(\"%%d: timeout\\n\", depth);", + " cpu_printf(\"%%d: timeout\\n\", depth);", "#endif", " goto Stutter;", " } }", @@ -2535,16 +3642,21 @@ " && !((trpt-1)->tau&4))", "/* blocks inside an atomic */ goto BreakOut;", "#ifdef DEBUG", - " printf(\"%%d: req timeout\\n\",", + " cpu_printf(\"%%d: req timeout\\n\",", " depth);", "#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);", + " cpu_printf(\"%%d: timeout\\n\", depth);", "#endif", " trpt->tau |= 1;", " goto Again;", @@ -2560,7 +3672,7 @@ " { 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 +3697,47 @@ "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(\"%%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", + "#ifndef SAFETY", " if (_n != 0", /* we made a move */ "#ifdef VERI", @@ -2601,7 +3754,7 @@ " 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 +3777,23 @@ " 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();", + " }", + " if (depth > 0)", + " {", + "#if NCORE>1 && defined(FULL_TRAIL)", + " if (upto > 0)", + " { Pop_Stack_Tree();", " }", "#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", + " goto Up;", " }", - " if (depth > 0) goto Up;", "}\n", "#else", "void new_state(void) { /* place holder */ }", "#endif", /* BFS */ "", "void", - "assert(int a, char *s, int ii, int tt, Trans *t)", + "spin_assert(int a, char *s, int ii, int tt, Trans *t)", "{", " if (!a && !noasserts)", " { char bad[1024];", @@ -2688,7 +3810,7 @@ "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;", "}", @@ -2697,10 +3819,10 @@ "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", "#if SYNC", " printf(\" %%8g nominal states (- rv and atomic)\\n\", nstates-midrv-nlinks+revrv);", @@ -2714,143 +3836,144 @@ " printf(\" %%8g revrv\\n\", revrv);", "#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);", + " #ifndef AUTO_RESIZE", + " if (hcmp > (double) (1< 100.)\\n\\n\",", + " (double)(((double) udmem) * 8.0) / (double) nstates);", + " else", " 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 0", " if (udmem)", - " printf(\"total bits available: %%8g (-M%%ld)\\n\",", + " { printf(\"total bits available: %%8g (-M%%ld)\\n\",", " ((double) udmem) * 8.0, udmem/(1024L*1024L));", - " else", -#endif - " printf(\"total bits available: %%8g (-w%%d)\\n\",", - " ((double) (1L << (ssize-4)) * 16.0), ssize);", + " } else", + " { printf(\"total bits available: %%8g (-w%%d)\\n\",", + " ((double) (ONE_L << (ssize-4)) * 16.0), ssize);", + " }", + " #endif", "#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", + "#ifdef BFS_DISK", + " 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;", + "{ double nr1, nr2, nr3 = 0.0, nr4, nr5 = 0.0;", "#if !defined(MA) && (defined(MEMCNT) || defined(MEMLIM))", " int mverbose = 1;", "#else", " int mverbose = verbose;", "#endif", + "#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\");", "#ifdef SC", " (void) unlink((const char *)stackfile);", "#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\");", "#endif", "#ifndef NOREDUCE", " printf(\" + Partial Order Reduction\\n\");", "#endif", -#if 0 - "#ifdef Q_PROVISO", - " printf(\" + Queue Proviso\\n\");", + "#ifdef REVERSE", + " printf(\" + Reverse Depth-First Search Order\\n\");", + "#endif", + "#ifdef T_REVERSE", + " printf(\" + Reverse Transition Ordering\\n\");", + "#endif", + "#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 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 +3983,8 @@ "#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\");", @@ -2905,9 +4029,13 @@ " 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,71 +4048,85 @@ " 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", + " #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\");", + " #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", -#ifndef POWOW " 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(\"%%9.3f\tactual memory usage for states\",", + " tmp_nr/1048576.);", + " remainder -= tmp_nr;", " printf(\" (\");", " if (tmp_nr > 0.)", " { if (tmp_nr > nr1) printf(\"unsuccessful \");", @@ -2994,50 +4136,87 @@ " printf(\"less than 1k)\\n\");", "#ifndef MA", " if (tmp_nr > 0.)", - " { printf(\"\tState-vector as stored = %%.0f byte\",", + " { 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));", + " (long int) sizeof(struct H_el)-sizeof(unsigned));", " }", "#endif", "#if !defined(MA) || defined(COLLAPSE)", - " printf(\"%%-6.3f\tmemory used for hash table (-w%%d)\\n\",", - " nr3/1000000., ssize);", - " remainder = remainder - nr3;", + " printf(\"%%9.3f\tmemory used for hash table (-w%%d)\\n\",", + " nr3/1048576., ssize);", + " 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.);", + " #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.);", + " if (fragment > 1048576.)", + " printf(\"%%9.3f\tmemory lost to fragmentation\\n\",", + " fragment/1048576.);", + " printf(\"%%9.3f\ttotal actual memory usage\\n\\n\",", + " memcnt/1048576.);", " }", - "#ifndef MA", + " #ifndef MA", " else", - "#endif", + " #endif", + "#endif", + + "#if !defined(BITSTATE) && defined(NOCOMP)", + "jump_here:", "#endif", + "#ifndef MA", - " printf(\"%%-6.3f\tmemory usage (Mbyte)\\n\\n\",", - " memcnt/1000000.);", + " printf(\"%%9.3f\tmemory usage (Mbyte)\\n\\n\",", + " memcnt/1048576.);", "#endif", "#ifdef COLLAPSE", " printf(\"nr of templates: [ globals chans procs ]\\n\");", " printf(\"collapse counts: [ \");", " { int i; for (i = 0; i < 256+2; i++)", " if (ncomps[i] != 0)", - " printf(\"%%d \", ncomps[i]);", + " printf(\"%%d \", (int) ncomps[i]);", " printf(\"]\\n\");", " }", "#endif", + " #ifdef TRIX", + " if (mverbose)", + " { 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 +4232,90 @@ "#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", " pan_exit(0);", "}\n", "void", "stopped(int arg)", "{ printf(\"Interrupted\\n\");", + "#if NCORE>1", + " was_interrupted = 1;", + "#endif", " wrapup();", " pan_exit(0);", "}", + "", + "#ifdef SFH", "/*", - " * based on Bob Jenkins hash-function from 1996", - " * see: http://www.burtleburtle.net/bob/", + " * 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__)) || defined(__WATCOMC__) \\", + " || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)", + " #define get16bits(d) (*((const uint16_t *) (d)))", + " #endif", + "", + " #ifndef get16bits", + " #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\\", + " +(uint32_t)(((const uint8_t *)(d))[0]) )", + " #endif", "", -"#if defined(HASH64) || defined(WIN64)", - /* 64-bit Jenkins hash: http://burtleburtle.net/bob/c/lookup8.c */ + "void", + "d_sfh(const char *s, int len)", + "{ 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;", + "}", + "#endif", /* SFH */ + "", + "#include ", /* uint32_t etc. */ + "#if defined(HASH64) || defined(WIN64)", + "/* 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,56 +4330,119 @@ " 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; \\", + "}", + "", + "#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;", + "#endif", "", + "void", + "d_hash(uchar *kb, int nbytes)", + "{ uint8_t *bp;", + "#if defined(HASH64) || defined(WIN64)", + " uint64_t a = 0, b, c, n;", + " uint64_t *k = (uint64_t *) kb;", + "#else", + " uint32_t a = 0, b, c, n;", + " 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 defined(HASH64) || defined(WIN64)", + " 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 defined(HASH64) || defined(WIN64)", " 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 = a&7; /* 1st bit */", + " j2 = b&nmask; j4 = (a>>3)&7; /* 2nd bit */", + " K1 = c; K2 = b;", "}", + "", "void", "s_hash(uchar *cp, int om)", - "{ d_hash(cp, om); /* sets K1 and K2 */", + "{", + "#if defined(SFH)", + " d_sfh((const char *) cp, om); /* sets K1 */", + "#else", + " d_hash(cp, om); /* sets K1 etc */", + "#endif", "#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;", + " j1_spin = K1&mask;", " else", - " j1 = K1;", + " j1_spin = K1;", "}", "#ifndef RANDSTOR", "int *prerand;", @@ -3150,13 +4461,159 @@ "}", "#endif", "", + "void", + "set_masks(void) /* 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 = ((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);", + " }", + "}", + "", + "static long reclaim_size;", + "static char *reclaim_mem;", + "#if defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(MA)", + "#if NCORE>1", + " #error cannot combine AUTO_RESIZE with NCORE>1 yet", + "#endif", + "static struct H_el **N_tab;", + "void", + "reverse_capture(struct H_el *p)", + "{ if (!p) return;", + " reverse_capture(p->nxt);", + " /* last element of list moves first */", + " /* to preserve list-order */", + " j2 = p->m_K1;", + " if (ssize < 8*WS) /* probably always true */", + " { j2 &= mask;", + " }", + " p->nxt = N_tab[j2];", + " N_tab[j2] = p;", + "}", + "void", + "resize_hashtable(void)", + "{", + " if (WS == 4 && ssize >= 27 - 1)", + " { return; /* cannot increase further */", + " }", + "", + " ssize += 2; /* 4x size @htable ssize */", + "", + " printf(\"pan: resizing hashtable to -w%%d.. \", ssize);", + "", + " N_tab = (struct H_el **)", + " emalloc((ONE_L<1", + "int", + "find_claim(char *s)", + "{ int i, j;", + " for (i = 0; procname[i] != \":np_:\"; 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", + "", "int", "main(int argc, char *argv[])", "{ void to_compile(void);\n", " efd = stderr; /* default */", + "", + " if (G_long != sizeof(long)", + " || G_int != sizeof(int))", + " { printf(\"spin: error, the version of spin \");", + " printf(\"that generated this pan.c assumed a different \");", + " printf(\"wordsize (%%d iso %%d)\\n\", G_long, (int) sizeof(long));", + " exit(1);", + " }", + "", + "#if defined(T_RAND) && (T_RAND>0)", + " s_rand = T_RAND;", /* so that -RS can override */ + "#elif defined(P_RAND) && (P_RAND>0)", + " s_rand = P_RAND;", + "#endif", /* else, could use time as seed... */ + "", + "#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 */", "#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", @@ -3169,9 +4626,13 @@ "#endif", " case 'A': noasserts = 1; break;", " case 'b': bounded = 1; break;", + "#ifdef HAS_CODE", + " case 'C': coltrace = 1; goto samething;", + "#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,14 +4642,32 @@ "#if !defined(SAFETY) && !defined(NOFAIR)", " case 'f': fairness = 1; break;", "#endif", + "#ifdef HAS_CODE", + " case 'g': gui = 1; goto samething;", + "#endif", " case 'h': if (!argv[1][2]) usage(efd); else", - " HASH_NR = atoi(&argv[1][2])%%33; break;", + " HASH_NR = atoi(&argv[1][2])%%100; break;", " case 'I': iterative = 2; every_error = 1; break;", " case 'i': iterative = 1; every_error = 1; break;", " case 'J': like_java = 1; break; /* Klaus Havelund */", "#ifdef BITSTATE", " case 'k': hfns = atoi(&argv[1][2]); break;", "#endif", + "#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;", @@ -3197,7 +4676,6 @@ " 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,36 +4684,100 @@ " 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(argv[1][2]))", + " whichclaim = atoi(&argv[1][2]);", + " else if (isalpha(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(argv[1][2]) && argc > 2 && argv[2][0] != '-')", + " { argc--; argv++;", + " }", + "#endif", +"#endif", + " break;\n", " case 'n': no_rck = 1; break;", + " case 'P': readtrail = 1; onlyproc = atoi(&argv[1][2]);", + " if (argv[2][0] != '-') /* check next arg */", + " { trailfilename = argv[2];", + " argc--; argv++; /* skip next arg */", + " }", + " break;", "#ifdef SVDUMP", " case 'p': vprefix = atoi(&argv[1][2]); break;", "#endif", + "#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;", + " case 'R':", + "#if defined(T_RAND) || defined(P_RAND) || defined(RANDSTOR)", + " if (argv[1][2] == 'S') /* e.g., -RS76842 */", + " { s_rand = atoi(&argv[1][3]);", + " } else", + "#endif", + " { Nrun = atoi(&argv[1][2]);", + " }", + " break;", "#ifdef HAS_CODE", " case 'r':", "samething: readtrail = 1;", " if (isdigit(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 '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;", + " case 'S': silent = 1; goto samething;", "#endif", - " case 'R': Nrun = atoi(&argv[1][2]); break;", "#ifdef BITSTATE", " case 's': hfns = 1; break;", "#endif", " case 'T': TMODE = 0444; break;", " case 't': if (argv[1][2]) tprefix = &argv[1][2]; break;", - " case 'V': printf(\"Generated by %%s\\n\", Version);", - " to_compile(); pan_exit(0); break;", - " case 'v': verbose = 1; 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]); break;", " case 'Y': signoff = 1; break;", " case 'X': efd = stdout; 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 that 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++;", @@ -3244,28 +4786,49 @@ " { TMODE = 0666;", " fprintf(efd, \"warning: -T ignored when -i or -I is used\\n\");", " }", + "#if defined(HASH32) && !defined(SFH)", + " if (WS > 4)", + " { fprintf(efd, \"strong warning: compiling -DHASH32 on a 64-bit machine\\n\");", + " fprintf(efd, \" without -DSFH can slow down performance a lot\\n\");", + " }", + "#endif", "#if defined(WIN32) || defined(WIN64)", " if (TMODE == 0666)", " TMODE = _S_IWRITE | _S_IREAD;", " else", " TMODE = _S_IREAD;", "#endif", - "#ifdef OHASH", - " fprintf(efd, \"warning: -DOHASH no longer supported (directive ignored)\\n\");", - "#endif", - "#ifdef JHASH", - " fprintf(efd, \"warning: -DJHASH no longer supported (directive ignored)\\n\");", - "#endif", - "#ifdef HYBRID_HASH", - " fprintf(efd, \"warning: -DHYBRID_HASH no longer supported (directive ignored)\\n\");", + "#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 NOCOVEST", - " fprintf(efd, \"warning: -DNOCOVEST 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 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);", @@ -3297,8 +4860,8 @@ " 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 +4870,90 @@ "#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);", - "#endif", - "#if defined(HAS_LAST)", - " fprintf(efd, \"error: -DBFS not compatible with _last\\n\");", - " exit(1);", - "#endif", - "#if defined(REACH)", - " fprintf(efd, \"warning: -DREACH redundant when -DBFS is used\\n\");", + " #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_STACK)", - " fprintf(efd, \"error: cannot use UnMatched qualifier on c_track with BFS\\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", "#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", + " #ifdef SFH", /* cannot happen -- undef-ed in this case */ + " #error cannot combine -DHC and -DSFH", + " /* use of NOCOMP is the real reason */", + " #else", + " #ifdef NOCOMP", + " #error cannot combine -DHC and -DNOCOMP", + " #endif", + " #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 SFH", + " #error cannot combine -DCOLLAPSE and -DSFH", + " /* use of NOCOMP is the real reason */", + " #else", + " #ifdef NOCOMP", + " #error cannot combine -DCOLLAPSE and -DNOCOMP", + " #endif", + " #endif", "#endif", " if (maxdepth <= 0 || ssize <= 1) usage(efd);", "#if SYNC>0 && !defined(NOREDUCE)", @@ -3382,28 +4966,17 @@ " }", "#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<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\");", + " #warning use of rendezvous with BFS does not preserve all invalid endstates", "#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 (!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 (!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", + " #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 **********************/ - + " set_masks();", "#ifdef BFS", " trail = (Trail *) emalloc(6*sizeof(Trail));", " trail += 3;", @@ -3570,14 +5105,14 @@ "#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);", "#endif", "#if SYNC>0 && ASYNC==0", " set_recvs();", @@ -3591,6 +5126,7 @@ "void", "usage(FILE *fd)", "{", + " fprintf(fd, \"%%s\\n\", SpinVersion);", " fprintf(fd, \"Valid Options are:\\n\");", "#ifndef SAFETY", "#ifdef NP", @@ -3606,6 +5142,7 @@ " 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\");", @@ -3622,6 +5159,9 @@ "#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,17 +5171,20 @@ " 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 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\");", @@ -3651,6 +5194,9 @@ " 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", + "#if defined(T_RAND) || defined(P_RAND) || defined(RANDSTOR)", + " fprintf(fd, \"\t-RSN use randomization seed N\\n\");", + "#endif", "#ifdef BITSTATE", " fprintf(fd, \"\t-RN repeat run Nx with N \");", " fprintf(fd, \"[1..32] independent hash functions\\n\");", @@ -3662,38 +5208,37 @@ " 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)", "{ 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)", + " { printf(\"pan: out of memory\\n\");", + "#ifdef MEMLIM", "err:", - "#endif", - " printf(\"pan: out of memory\\n\");", - "#if defined(MEMCNT) || defined(MEMLIM)", " printf(\"\t%%g bytes used\\n\", memcnt);", " printf(\"\t%%g bytes more needed\\n\", (double) n);", - " printf(\"\t%%g bytes limit\\n\",", - " memlim);", + " printf(\"\t%%g bytes limit\\n\", memlim);", "#endif", "#ifdef COLLAPSE", " printf(\"hint: to reduce memory, recompile with\\n\");", @@ -3714,6 +5259,15 @@ " 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;", @@ -3757,6 +5311,9 @@ "Uerror(char *str)", "{ /* always fatal */", " uerror(str);", + "#if NCORE>1", + " sudden_stop(\"Uerror\");", + "#endif", " wrapup();", "}\n", "#if defined(MA) && !defined(SAFETY)", @@ -3820,7 +5377,7 @@ " 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,\", ", @@ -3868,8 +5425,15 @@ "", " 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 +5455,16 @@ " depth = od;", " }", "#endif", -"#ifdef BFS", + "#if NCORE>1", + " writing_trail = 1;", + "#endif", + "#ifdef BFS", " if (depth > 1) trpt--;", " nuerror(str);", " if (depth > 1) trpt++;", -"#else", + "#else", " putrail();", -"#endif", + "#endif", "#if defined(MA) && !defined(SAFETY)", " if (strstr(str, \" cycle\"))", " { if (every_error)", @@ -3905,20 +5472,33 @@ " 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)", + " {", + "#if NCORE>1", + " sudden_stop(\"uerror\");", + "#endif", " wrapup();", + " }", " depthfound = -1;", "}\n", "int", @@ -3930,13 +5510,14 @@ " || 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 +5532,107 @@ "}\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++)", + "#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 +5640,16 @@ " 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 +5669,16 @@ "#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 +5688,9 @@ "#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 +5701,130 @@ " 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", + "#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", + " #ifndef NOCOMP", " 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", + " #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 (BASE > 0 && h > 0)", " ((P0 *)pptr(h))->_pid = h-BASE;", " else", " ((P0 *)pptr(h))->_pid = h;", - " i = stack->o_delqs;", + "#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", + " 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", + "#ifndef TRIX", " 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", + " #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", - " if (!stack->lst) /* debugging */", + "#endif", + " if (!stack->lst)", " Uerror(\"error: q_restor\");", " stack = stack->lst;", "}", @@ -4163,7 +5867,46 @@ "#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 +5915,104 @@ " 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];", - "#ifndef NOVSZ", - " now._vsz = vsize;", - "#endif", - "#ifndef NOCOMP", + " #ifndef NOCOMP", " for (i = vsize; i < o_vsize; i++)", " Mask[i] = 0; /* reset */", + " #endif", + "#endif", + "#ifndef NOVSZ", + " now._vsz = vsize;", "#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;", + "#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", + " #if VECTORSZ>32000", " stack->o_skip = (int) q_skip[h];", - "#else", + " #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];", + " #ifndef NOCOMP", + " for (k = vsize; k < o_vsize; k++)", + " Mask[k] = 0; /* reset */", + " #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)", @@ -4297,31 +6064,29 @@ " /* for (i = 0; i < n; i++) printf(\"%%d,\", v[i]); */", " printf(\"\\n\");", " }", - " printf(\"%%d: cycle check starts\\n\", depth);", + " 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 + "#ifndef NOFAIR", " now._cnt[1] = now._cnt[0];", -#endif - "#endif", + "#endif", " memcpy((char *)&A_Root, (char *)&now, vsize);", " A_depth = depthfound = depth;", + + "#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", " 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", @@ -4367,8 +6132,39 @@ " 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));", + + "#if NCORE>1", + "struct H_el *", + "grab_state(int n)", + "{ struct H_el *grab_shared(int);", + " return grab_shared(sizeof(struct H_el)+n-sizeof(unsigned));", + "}", + "#else", + " #ifndef AUTO_RESIZE", + " #define grab_state(n) (struct H_el *) \\", + " emalloc(sizeof(struct H_el)+n-sizeof(unsigned long));", + " #else", + " struct H_el *", + " grab_state(int n)", + " { struct H_el *p;", + " int cnt = sizeof(struct H_el)+n-sizeof(unsigned long);", + "", + " if (reclaim_size >= cnt+WS)", + " { if ((cnt & (WS-1)) != 0) /* alignment */", + " { cnt += WS - (cnt & (WS-1));", + " }", + " p = (struct H_el *) reclaim_mem;", + " reclaim_mem += cnt;", + " reclaim_size -= cnt;", + " memset(p, 0, cnt);", + " } else", + " { p = (struct H_el *) emalloc(cnt);", + " }", + " return p;", + " }", + " #endif", + "#endif", + "#endif", "#ifdef COLLAPSE", "unsigned long", @@ -4376,15 +6172,18 @@ "{ struct H_el *tmp, *ntmp; long m;", " struct H_el *olst = (struct H_el *) 0;", " s_hash((uchar *)v, n);", - " tmp = H_tab[j1];", + + "#if 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 +6191,7 @@ "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 +6209,29 @@ " else if (!tmp->nxt)", " goto Append;", " }", + "#if NCORE>1 && !defined(SEP_STATE)", + " enter_critical(GLOBAL_LOCK);", + "#endif", " m = ++ncomps[tp];", + "#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); /* uses spinlock */", + "#endif", + "#ifdef FULLSTACK", " return tmp->tagged;", "#else", @@ -4600,11 +6413,58 @@ " 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;", + " }", + "#if 1", + " n = i = v - (char *)&comp_now; /* bytes written so far */", + "#endif", + " 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);", @@ -4630,7 +6490,13 @@ "onstack_zap(void)", "{ struct H_el *v, *w, *last = 0;", " struct H_el **tmp = H_tab;", - " char *nv; int n, m;\n", + " 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 +6514,7 @@ " 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,14 +6522,21 @@ " 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;", @@ -4672,39 +6545,57 @@ " 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;", + "#if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)", + " uchar was_last = now._last;", + " now._last = 0;", + "#endif", " H_tab = S_Tab;", " if (hstore((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)", "{ struct H_el *tmp;", " struct 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)", @@ -4722,13 +6613,16 @@ " s_hash((uchar *)v, n);", "#endif", " H_tab = tmp2;", - " for (tmp = S_Tab[j1]; tmp; Zn++, tmp = tmp->nxt)", + " for (tmp = S_Tab[j1_spin]; tmp; Zn++, tmp = tmp->nxt)", " { m = memcmp(((char *)&(tmp->state)),v,n);", " if (m <= 0)", " { Lstate = (struct H_el *) tmp;", " break;", " } }", " PROBE++;", + "#if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)", + " now._last = was_last;", + "#endif", " return (m == 0);", "}", "#endif", @@ -4738,19 +6632,32 @@ "void", "hinit(void)", "{", -"#ifdef MA", - "#ifdef R_XPT", - " { void r_xpoint(void);", - " r_xpoint();", - " }", - "#else", - " dfa_init((unsigned short) (MA+a_cycles));", - "#endif", -"#endif", -"#if !defined(MA) || defined(COLLAPSE)", - " H_tab = (struct H_el **)", - " emalloc((1L<1 && !defined(COLLAPSE)", + " if (!readtrail)", + " { void init_HT(unsigned long);", + " init_HT(0L);", + " }", + "#endif", + "#endif", + " #endif", + " #if !defined(MA) || defined(COLLAPSE)", + "#if NCORE>1", + " if (!readtrail)", + " { void init_HT(unsigned long);", + " init_HT((unsigned long) (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 = (unsigned int) 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;", + " }", + "", + "#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 +6738,17 @@ " { 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 +6757,29 @@ " 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", + "done:", + "#if NCORE>1 && !defined(SEP_STATE)", + " leave_critical(GLOBAL_LOCK);", "#endif", - " return 1; /* old state */", + " return ret_val; /* old state */", "}", "#endif", @@ -4873,34 +6799,138 @@ "}", "#endif", + "#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", + "again:", + " for (i = 0; i < bound; i++)", + " { if (base[i] != NULL)", + " { struct 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", + " { struct H_el *ntmp, *olst = (struct 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 (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;", + " }", + "#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", "int", "hstore(char *vin, int nin) /* hash table storage */", - "{ struct H_el *tmp, *ntmp, *olst = (struct H_el *) 0;", + "{ struct H_el *ntmp;", + " struct H_el *tmp, *olst = (struct 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 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", + " #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,15 +6941,30 @@ "#endif", " m = 0;", " }", - "#endif", + " #endif", "#endif", "#if !defined(HC) && !(defined(BITSTATE) && defined(LC))", " s_hash((uchar *)v, n);", "#endif", - " tmp = H_tab[j1];", + "#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)", + " enter_critical(CS_ID); /* uses spinlock */", + "#endif", + + " tmp = H_tab[j1_spin];", " if (!tmp)", " { tmp = grab_state(n);", - " H_tab[j1] = tmp;", + "#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 */", @@ -4971,6 +7016,10 @@ "#endif", "#endif", + "#if NCORE>1", + " Lstate = (struct H_el *) tmp;", + "#endif", + "#ifdef FULLSTACK", "#ifndef SAFETY", /* or else wasnew == 0 */ " if (wasnew)", @@ -4982,17 +7031,31 @@ " {", "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 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 NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)", + " leave_critical(CS_ID);", + "#endif", " return 0;", " } else", "#endif", @@ -5014,41 +7077,95 @@ " 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 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 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", + "#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 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 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", - " printf(\"\t\tReVisiting (from smaller depth)\\n\");", - "#endif", - " nstates--;", + " 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 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,22 +7173,34 @@ 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;", - " }", + " return 0;", + " }", "#endif", - "#if defined(BFS) && defined(Q_PROVISO)", + "#if (defined(BFS) && defined(Q_PROVISO)) || NCORE>1", " Lstate = (struct H_el *) tmp;", "#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;", @@ -5082,18 +7211,36 @@ "Append:", "#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", " 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(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", @@ -5116,24 +7263,38 @@ " }", "#endif", "#endif", + "#if defined(AUTO_RESIZE) && !defined(BITSTATE)", + " tmp->m_K1 = K1;", + "#endif", " memcpy(((char *)&(tmp->state)), v, n);", "#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", + " #ifdef DEBUG", + " dumpstate(-1, v, n, 0);", + " #endif", + " #if NCORE>1", + " Lstate = (struct H_el *) tmp;", + " #endif", + "#endif", + + "/* #if NCORE>1 && !defined(SEP_STATE) */", + "#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;", "}", "#endif", "#include TRANSITIONS", - "void", - "do_reach(void)", - "{", 0, }; --- /sys/src/cmd/spin/pangen2.c Thu Nov 17 15:29:08 2011 +++ /sys/src/cmd/spin/pangen2.c Thu Nov 17 15:28:50 2011 @@ -1,6 +1,6 @@ /***** spin: pangen2.c *****/ -/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ +/* Copyright (c) 1989-2009 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 */ @@ -8,6 +8,7 @@ /* Software written by Gerard J. Holzmann. For tool documentation see: */ /* http://spinroot.com/ */ /* Send all bug-reports and/or questions to: bugs@spinroot.com */ +/* (c) 2007: small additions for V5.0 to support multi-core verifications */ #include "spin.h" #include "version.h" @@ -20,24 +21,25 @@ #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 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; +extern int u_sync, u_async, nrRdy, Unique; extern int GenCode, IsGuard, Level, TestOnly; extern short has_stack; extern char *NextLab[]; -FILE *tc, *th, *tt, *tm, *tb; +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; @@ -52,9 +54,7 @@ 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 */ int mst=0; /* max nr of state/process */ int claimnr = -1; /* claim process, if any */ int eventmapnr = -1; /* event trace, if any */ @@ -74,8 +74,11 @@ 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 _ */ int has_global(Lextok *); +void Fatal(char *, char *); static int getweight(Lextok *); static int scan_seq(Sequence *); static void genconditionals(void); @@ -98,12 +101,31 @@ 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);\n", q->tn); +} + +static void +forward_procs(RunList *q) +{ + if (!q) return; + fprintf(tc, " Addproc(%d);\n", q->tn); + forward_procs(q->nxt); } static void @@ -111,6 +133,15 @@ { fprintf(th, "#define _T5 %d\n", uniq++); fprintf(th, "#define _T2 %d\n", uniq++); + + 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"); + } + fprintf(tm, "\tcase _T5:\t/* np_ */\n"); if (separate == 2) @@ -151,51 +182,72 @@ void gensrc(void) { ProcList *p; + int i; + + disambiguate(); /* avoid name-clashes between scopes */ - 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 */ + 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); + 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", (int) sizeof(int)); + + fprintf(th, "#ifdef WIN64\n"); + fprintf(th, " #define ONE_L ((unsigned long) 1)\n"); + fprintf(th, " #define long long long\n"); + fprintf(th, "#else\n"); + fprintf(th, " #define ONE_L (1L)\n"); + fprintf(th, "#endif\n"); + if (separate != 2) - fprintf(th, "char *TrailFile = Source; /* default */\n"); + { fprintf(th, "char *TrailFile = PanSource; /* default */\n"); + fprintf(th, "char *trailfilename;\n"); + } fprintf(th, "#if defined(BFS)\n"); - fprintf(th, "#ifndef SAFETY\n"); - fprintf(th, "#define SAFETY\n"); - fprintf(th, "#endif\n"); - fprintf(th, "#ifndef XUSAFE\n"); - fprintf(th, "#define XUSAFE\n"); - fprintf(th, "#endif\n"); + fprintf(th, " #ifndef SAFETY\n"); + fprintf(th, " #define SAFETY\n"); + fprintf(th, " #endif\n"); + fprintf(th, " #ifndef XUSAFE\n"); + fprintf(th, " #define XUSAFE\n"); + fprintf(th, " #endif\n"); fprintf(th, "#endif\n"); fprintf(th, "#ifndef uchar\n"); - fprintf(th, "#define uchar unsigned char\n"); + fprintf(th, " #define uchar unsigned char\n"); fprintf(th, "#endif\n"); fprintf(th, "#ifndef uint\n"); - fprintf(th, "#define uint unsigned int\n"); + fprintf(th, " #define uint unsigned int\n"); fprintf(th, "#endif\n"); if (sizeof(void *) > 4) /* 64 bit machine */ - { fprintf(th, "#ifndef HASH32\n"); - fprintf(th, "#define HASH64\n"); + { fprintf(th, "#if !defined(HASH32) && !defined(HASH64)\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)); 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) @@ -212,15 +264,21 @@ fprintf(th, "#define DELTA %d\n", DELTA); fprintf(th, "#ifdef MA\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#define MA 100\n"); + fprintf(th, " #undef MA\n"); + fprintf(th, " #define MA 100\n"); fprintf(th, "#endif\n#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,6 +288,8 @@ 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); if (has_last) fprintf(th, "#define HAS_LAST %d\n", has_last); if (has_sorted) @@ -239,8 +299,11 @@ 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 */ + 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"); + fprintf(th, "#define HAS_STACK %d\n", has_stack); if (has_enabled) fprintf(th, "#define HAS_ENABLED 1\n"); if (has_unless) @@ -256,7 +319,7 @@ || 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,18 +328,31 @@ 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) @@ -291,7 +367,7 @@ fprintf(th, " char *fnm; int from; int 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,6 +380,10 @@ case 2: fprintf(tc, "#include \"pan_t.h\"\n"); break; } + 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"); plunk_c_fcts(tc); /* State can be used in fcts */ @@ -314,9 +394,9 @@ fprintf(tc, "extern int verbose; extern long depth;\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 +415,7 @@ 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) @@ -360,12 +440,12 @@ fprintf(tm, "#define rand pan_rand\n"); fprintf(tm, "#if defined(HAS_CODE) && defined(VERBOSE)\n"); - fprintf(tm, " printf(\"Pr: %%d Tr: %%d\\n\", II, t->forw);\n"); + fprintf(tm, " cpu_printf(\"Pr: %%d Tr: %%d\\n\", II, t->forw);\n"); fprintf(tm, "#endif\n"); fprintf(tm, " switch (t->forw) {\n"); } else { fprintf(tt, "#ifndef PEG\n"); - 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"); @@ -374,7 +454,7 @@ fprintf(tm, "#define rand pan_rand\n"); fprintf(tm, "#if defined(HAS_CODE) && defined(VERBOSE)\n"); - fprintf(tm, " printf(\"Pr: %%d Tr: %%d\\n\", II, forw);\n"); + fprintf(tm, " cpu_printf(\"Pr: %%d Tr: %%d\\n\", II, forw);\n"); fprintf(tm, "#endif\n"); fprintf(tm, " switch (forw) {\n"); } @@ -404,11 +484,12 @@ fprintf(tb, " case 0: goto R999; /* nothing to undo */\n"); for (p = rdy; p; p = p->nxt) - putproc(p); - + { putproc(p); + } if (separate != 2) - { fprintf(th, "struct {\n"); + { + fprintf(th, "struct {\n"); fprintf(th, " int tp; short *src;\n"); fprintf(th, "} src_all[] = {\n"); for (p = rdy; p; p = p->nxt) @@ -416,9 +497,12 @@ 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"); + + fprintf(th, "S_F_MAP *flref[] = {\n"); /* 5.3.0 */ + for (p = rdy; p; p = p->nxt) + { fprintf(th, " src_file%d%c\n", p->tn, p->nxt?',':' '); + } + fprintf(th, "};\n"); } gencodetable(th); @@ -456,18 +540,27 @@ if (!run) fatal("no runable process", (char *)0); fprintf(tc, "void\n"); fprintf(tc, "active_procs(void)\n{\n"); +#if 1 + fprintf(tc, " if (!permuted) {\n"); + reverse_procs(run); + fprintf(tc, " } else {\n"); + forward_procs(run); + fprintf(tc, " }\n"); +#else reverse_procs(run); +#endif 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, " long peg[NTRANS];\n"); fprintf(th, "#endif\n"); - + fprintf(th, "void select_claim(int);\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"); @@ -475,9 +568,9 @@ 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 *reached[];\n"); @@ -491,7 +584,7 @@ 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,8 +602,6 @@ 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); @@ -537,13 +628,13 @@ 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]; }; @@ -717,7 +808,7 @@ { 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 @@ -727,16 +818,16 @@ 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", 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; } @@ -744,15 +835,19 @@ 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); - 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); + 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 +856,6 @@ { 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,8 +1041,8 @@ 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"); @@ -1024,7 +1118,7 @@ struct CaseCache *nxt; } CaseCache; -CaseCache *casing[6]; +static CaseCache *casing[6]; static int identical(Lextok *p, Lextok *q) @@ -1076,6 +1170,9 @@ if (stopat) while (f && f->seqno != stopat) { f = findnext(f); + if (!f) + { break; + } switch (f->n->ntyp) { case GOTO: case '.': @@ -1084,8 +1181,7 @@ break; default: return f; - } - } + } } return (Element *) 0; } @@ -1107,18 +1203,16 @@ 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 * @@ -1258,18 +1352,18 @@ } 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/* dead %d: %s */ ", u->special, u->var->name); switch (u->special) { @@ -1281,10 +1375,10 @@ } 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 +1386,20 @@ 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 @@ -1412,7 +1506,7 @@ { 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,15 +1533,15 @@ 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", e->merge_start, e->merge, e->merge_in, @@ -1457,8 +1551,8 @@ 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", @@ -1467,7 +1561,7 @@ 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 +1576,29 @@ 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"); +/* 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"); + fprintf(tm, "\t\t{ static int reported%d = 0;\n", e->seqno); + fprintf(tm, "\t\t int nn = (int) ((Pclaim *)this)->_n;\n\t\t"); + fprintf(tm, " if (verbose && !reported%d)\n\t\t", e->seqno); + fprintf(tm, " {\tprintf(\"depth %%ld: Claim %%s (%%d), state %%d (line %%d)\\n\",\n\t\t"); + fprintf(tm, " \t\tdepth, procname[spin_c_typ[nn]], nn, "); + fprintf(tm, "(int) ((Pclaim *)this)->_p, src_claim[ (int) ((Pclaim *)this)->_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"); 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, " { printf(\"depth %%d: Claim, state %%d (line %%d)\\n\",\n\t\t"); + fprintf(tm, " (int) depth, (int) ((Pclaim *)this)->_p, "); + fprintf(tm, "src_claim[ (int) ((Pclaim *)this)->_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 +1609,32 @@ 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 +1652,8 @@ 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 */ @@ -1758,8 +1863,8 @@ { 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: warning, %s:%d: 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 +1972,7 @@ 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: @@ -1888,6 +1993,26 @@ } 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; SeqList *h; @@ -1896,20 +2021,22 @@ { 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 +2064,25 @@ 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; if (!n) return 0; if (AllGlobal) return 1; /* global provided clause */ @@ -1975,7 +2118,8 @@ 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); @@ -2021,7 +2165,7 @@ else if (IsGuard) fprintf(fd, "%s%s", NextLab[Level], str); else - fprintf(fd, "Uerror(\"block in step seq\")%s", str); + fprintf(fd, "Uerror(\"block in d_step seq\")%s", str); } #define cat0(x) putstmnt(fd,now->lft,m); fprintf(fd, x); \ @@ -2070,12 +2214,14 @@ else fprintf(fd, "((trpt->tau)&1)"); if (GenCode) - printf("spin: line %3d, warning: 'timeout' in d_step sequence\n", - lineno); + printf("spin: warning, %s:%d, '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); @@ -2087,16 +2233,15 @@ fatal("'run' in d_step sequence (use atomic)", (char *)0); - fprintf(fd,"addproc(%d", fproc(now->sym->name)); + fprintf(fd,"addproc(II, %d", 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"); @@ -2180,7 +2325,7 @@ 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,10 +2353,16 @@ 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"); @@ -2256,9 +2407,9 @@ 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 +2425,7 @@ 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 +2493,13 @@ 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) @@ -2415,6 +2569,7 @@ fprintf(fd, ", 0, 0"); fprintf(fd, "))) "); Bailout(fd, ""); + if (!GenCode) { fprintf(fd, ";\n\t\t"); if (multi_oval) { check_needed(); @@ -2424,6 +2579,7 @@ } else fprintf(fd, "(trpt+1)->bup.oval = "); fprintf(fd, "XX"); + } } if (has_enabled) @@ -2485,7 +2641,7 @@ && 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 +2657,7 @@ if (v->lft->ntyp != CONST && v->lft->ntyp != EVAL + && v->lft->sym != NULL && strcmp(v->lft->sym->name, "_") != 0) { nocast=1; _isok++; @@ -2515,6 +2672,7 @@ 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)) @@ -2748,14 +2906,16 @@ break; case C_CODE: - fprintf(fd, "/* %s */\n\t\t", now->sym->name); + if (now->sym) + 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) + 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"); @@ -2768,7 +2928,7 @@ if (has_enabled) fprintf(fd, "if (TstOnly) return 1;\n\t\t"); - cat3("assert(", now->lft, ", "); + cat3("spin_assert(", now->lft, ", "); terse = nocast = 1; cat3("\"", now->lft, "\", II, tt, t)"); terse = nocast = 0; @@ -2797,16 +2957,30 @@ break; default: - printf("spin: bad node type %d (.m) - line %d\n", - now->ntyp, now->ln); + printf("spin: error, %s:%d, bad node type %d (.m)\n", + now->fn->name, now->ln, now->ntyp); fflush(tm); 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) @@ -2824,7 +2998,7 @@ if (!s->type) { if (strcmp(pre, ".") != 0) - non_fatal("undeclared variable '%s'", s->name); + fatal("undeclared variable '%s'", s->name); s->type = INT; } @@ -2845,22 +3019,29 @@ fatal("attempt to read value of '_'", 0); } } - if (withprocname - && s->context - && strcmp(pre, ".")) - fprintf(fd, "%s:", s->context->name); + ptr = s->name; + + if (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,11 +3066,27 @@ || (!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, ""); } --- /sys/src/cmd/spin/pangen2.h Thu Nov 17 15:29:24 2011 +++ /sys/src/cmd/spin/pangen2.h Thu Nov 17 15:29:15 2011 @@ -1,6 +1,6 @@ /***** spin: pangen2.h *****/ -/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ +/* Copyright (c) 1989-2007 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 */ @@ -8,20 +8,7 @@ /* Software written by Gerard J. Holzmann. For tool documentation see: */ /* http://spinroot.com/ */ /* Send all bug-reports and/or questions to: bugs@spinroot.com */ - -static char *Nvr1[] = { /* allow separate compilation */ - "#ifdef VERI", - "void", - "check_claim(int st)", - "{", - " if (st == endclaim)", - " uerror(\"claim violated!\");", - " if (stopstate[VERI][st])", - " uerror(\"end state in claim reached\");", - "}", - "#endif", - 0, -}; +/* (c) 2007: small additions for V5.0 to support multi-core verifications */ static char *Pre0[] = { "#ifdef SC", @@ -38,11 +25,12 @@ "#include ", "#else", "#include ", - "#include ", /* new 4.3.0 */ + "#include ", "#endif", "#include ", /* defines off_t */ "#include ", "#include ", + "#define Offsetof(X, Y) ((unsigned long)(&(((X *)0)->Y)))", "#ifndef max", "#define max(a,b) (((a)<(b)) ? (b) : (a))", @@ -55,10 +43,13 @@ static 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 +59,13 @@ * 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", @@ -93,32 +84,62 @@ " }", "#endif", "#endif", + + "#ifndef NO_V_PROVISO", + "#define V_PROVISO", + "#endif", + "#if !defined(NO_RESIZE) && !defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(SPACE) && NCORE==1", + " #define AUTO_RESIZE", + "#endif", + "", "struct H_el {", " struct H_el *nxt;", "#ifdef FULLSTACK", " unsigned int tagged;", - "#if defined(BITSTATE) && !defined(NOREDUCE) && !defined(SAFETY)", + " #if defined(BITSTATE) && !defined(NOREDUCE) && !defined(SAFETY)", " unsigned int proviso;", /* uses just 1 bit 0/1 */ - "#endif", + " #endif", "#endif", "#if defined(CHECK) || (defined(COLLAPSE) && !defined(FULLSTACK))", " unsigned long st_id;", "#endif", + "#if !defined(SAFETY) || defined(REACH)", + " unsigned int 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", + " #if VECTORSZ<65536", " unsigned short ln;", /* length of vector */ - "#else", + " #else", " unsigned long ln;", /* length of vector */ - "#endif", + " #endif", "#endif", - "#if !defined(SAFETY) || defined(REACH)", - " unsigned int D;", + "#if defined(AUTO_RESIZE) && !defined(BITSTATE)", + " unsigned long m_K1;", "#endif", - " unsigned state;", + " unsigned long state;", "} **H_tab, **S_Tab;\n", "typedef struct Trail {", " int st; /* current state */", + " int o_tt;", " uchar pr; /* process id */", " uchar tau; /* 8 bit-flags */", " uchar o_pm; /* 8 more bit-flags */", @@ -142,6 +163,9 @@ " 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", @@ -150,23 +174,22 @@ "#endif", " uchar o_m;", "#ifdef EVENT_TRACE", - "#if nstates_event<256", - " uchar o_event;", - "#else", - " unsigned short o_event;", - "#endif", + " #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", + " #ifdef T_RAND", + " 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)", + "#if (defined(FULLSTACK) && !defined(MA)) || defined(BFS) || (NCORE>1)", " struct H_el *ostate; /* pointer to stored state */", "#endif", /* CNTRSTACK when !NOREDUCE && BITSTATE && SAFETY, uses LL[] */ @@ -174,6 +197,23 @@ " 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", @@ -188,6 +228,22 @@ "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", + "#ifdef PERMUTED", + " uchar permuted = 1;", + "#else", + " uchar permuted = 0;", + "#endif", + "double quota; /* time limit */", + "#if NCORE>1", + "long z_handoff = -1;", + "#endif", "#ifdef SC", /* stack cycling */ "char *stackfile;", "#endif", @@ -195,7 +251,10 @@ "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;", @@ -203,6 +262,62 @@ "static double fragment = (double) 0;", "static unsigned long grow;", "", +#if 1 + "unsigned int HASH_CONST[] = {", + " /* asuming 4 bytes per int */", + " 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,", + " 0", + "};", +#else "unsigned int HASH_CONST[] = {", " /* asuming 4 bytes per int */", " 0x88888EEF, 0x00400007,", @@ -224,9 +339,23 @@ " 0x273d1aa5, 0x8923b1dd,", " 0", "};", - "int mreached=0, done=0, errors=0, Nrun=1;", +#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 PUTPID", + "char *progname;", + "#endif", + "#if defined(ZAPH) && defined(BITSTATE)", + "double zstates = 0;", + "#endif", + "int c_init_run;", "#ifdef BFS", "double midrv=0, failedrv=0, revrv=0;", "#endif", @@ -236,9 +365,11 @@ "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;", + "int state_tables=0, fairness=0, no_rck=0, Nr_Trails=0, dodot=0;", "char simvals[128];", "#ifndef INLINE", "int TstOnly=0;", @@ -251,7 +382,7 @@ "#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);", @@ -264,8 +395,15 @@ "extern int dfa_store(uchar *);", "unsigned int maxgs = 0;", "#endif", - - "State comp_now; /* compressed state vector */", + "", + "#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", + "", "State comp_msk;", "uchar *Mask = (uchar *) &comp_msk;", "#ifdef COLLAPSE", @@ -273,23 +411,30 @@ "static char *scratch = (char *) &comp_tmp;", "#endif", - "Stack *stack; /* for queues, processes */", + "_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 j1_spin; /* 5.2.1: avoid nameclash with math.h */", "static unsigned long K1, K2;", "static unsigned long j2, j3, j4;", "#ifdef BITSTATE", -#ifndef POWOW "static long udmem;", -#endif "#endif", "static long A_depth = 0;", - "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;", + "long depth = 0;", + /* depth: not static to support -S2, but possible clash with embedded code */ + "#if NCORE>1", + "long nr_handoffs = 0;", + "#endif", + "static uchar warned = 0, iterative = 0, exclusive = 0, like_java = 0, every_error = 0;", "static uchar noasserts = 0, noends = 0, bounded = 0;", + + "#if defined(T_RAND) || defined(P_RAND) || defined(RANDSTOR)", + "unsigned int s_rand = 123; /* default seed */", + "#endif", + "#if SYNC>0 && ASYNC==0", "void set_recvs(void);", "int no_recvs(int);", @@ -304,15 +449,13 @@ "#ifdef BITSTATE", "int (*bstore)(char *, int);", "int bstore_reg(char *, int);", -#ifndef POWOW "int bstore_mod(char *, int);", -#endif "#endif", "void active_procs(void);", "void cleanup(void);", "void do_the_search(void);", "void find_shorter(int);", - "void iniglobals(void);", + "void iniglobals(int);", "void stopped(int);", "void wrapup(void);", "int *grab_ints(int);", @@ -425,9 +568,9 @@ "}", "#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 lstate[])", " /* process n, with m states, is=initial state */", - "{ Trans *T0, *T1, *T2, *T3;", + "{ Trans *T0, *T1, *T2, *T3, *T4, *T5;", " int i, k;", "#ifndef NOREDUCE", " int g, h, j, aa;", @@ -436,7 +579,7 @@ " 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 +620,7 @@ " } 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 +633,9 @@ "#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 +647,7 @@ " 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 +655,7 @@ " 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 +671,8 @@ " * 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 +683,8 @@ " 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 +702,21 @@ " { 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 +812,43 @@ " 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);", + " } 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,17 +871,75 @@ " printf(\" 'else' stmnts\\n\");", " pan_exit(1);", " } }", - " if (!state_tables && strcmp(procname[n], \":never:\") == 0)", - " { int h = 0;", - " 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));", + "#ifndef LOOPSTATE", + " if (state_tables)", + "#endif", + " do_dfs(n, m, is, srcln, reach, lstate);", + "#ifdef T_REVERSE", + " /* 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 */", + "", + " /* 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)", - " frm_st0[T0->forw] = i;", + " crack(n, i, T0, srcln);", " }", + "#endif", "}", "void", "imed(Trans *T, int v, int n, int j) /* set intermediate state */", @@ -731,7 +957,12 @@ " 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", @@ -748,6 +979,44 @@ " }", "}", "void", + "dfs_table(int n, int m, int is, short srcln[], uchar reach[], uchar lstate[])", + "{ 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 */", + " { lstate[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)", + " {", + "#ifdef HAS_UNLESS", + " int i, j;", + "#endif", + " dfs_table(n, m, z->st, srcln, reach, lstate);", + "#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, lstate);", + " }", + "#endif", + " }", + " reach[is] &= ~16; /* no longer on stack */", + "}", + "void", + "do_dfs(int n, int m, int is, short srcln[], uchar reach[], uchar lstate[])", + "{ int i;", + " dfs_table(n, m, is, srcln, reach, lstate);", + " for (i = 0; i < m; i++)", + " reach[i] &= ~(4|8|16);", + "}", + "void", "crack(int n, int j, Trans *z, short srcln[])", "{ int i;\n", " if (!z) return;", @@ -765,19 +1034,19 @@ " }", "#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])", @@ -787,6 +1056,32 @@ " }", " 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", --- /sys/src/cmd/spin/pangen3.c Thu Nov 17 15:29:35 2011 +++ /sys/src/cmd/spin/pangen3.c Thu Nov 17 15:29:28 2011 @@ -13,10 +13,10 @@ #include "y.tab.h" extern FILE *th; -extern int claimnr, eventmapnr; +extern int eventmapnr; typedef struct SRC { - short ln, st; /* linenr, statenr */ + int ln, st; /* linenr, statenr */ Symbol *fn; /* filename */ struct SRC *nxt; } SRC; @@ -28,6 +28,8 @@ static SRC *frst = (SRC *) 0; static SRC *skip = (SRC *) 0; +extern int ltl_mode; + extern void sr_mesg(FILE *, int, int); static void @@ -47,7 +49,7 @@ return; if (lastfnm) - fprintf(th, "{ %s, %d, %d },\n\t", + fprintf(th, "{ \"%s\", %d, %d },\n\t", lastfnm->name, lastfrom, j-1); @@ -59,7 +61,7 @@ putfnm_flush(int j) { if (lastfnm) - fprintf(th, "{ %s, %d, %d }\n", + fprintf(th, "{ \"%s\", %d, %d }\n", lastfnm->name, lastfrom, j); } @@ -72,7 +74,7 @@ if (tmp->st == m) return; tmp = (SRC *) emalloc(sizeof(SRC)); - tmp->st = (short) m; + tmp->st = m; tmp->nxt = skip; skip = tmp; } @@ -85,7 +87,7 @@ if (tmp->st == m) { if (tmp == skip) skip = skip->nxt; - else + else if (lst) /* always true, but helps coverity */ lst->nxt = tmp->nxt; break; } @@ -104,13 +106,13 @@ for (tmp = frst; 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; + tmp->ln = n; + tmp->st = m; tmp->fn = e->n->fn; tmp->nxt = frst; frst = tmp; @@ -137,8 +139,9 @@ putnr(0); } fprintf(th, "};\n"); - if (m == claimnr) - fprintf(th, "#define reached_claim reached%d\n", m); + + fprintf(th, "uchar *loopstate%d;\n", m); + if (m == eventmapnr) fprintf(th, "#define reached_event reached%d\n", m); @@ -149,6 +152,7 @@ dumpsrc(int n, int m) { SRC *tmp, *lst; int j; + static int did_claim = 0; fprintf(th, "short src_ln%d [] = {\n\t", m); for (j = 0, col = 0; j <= n; j++) @@ -164,7 +168,7 @@ fprintf(th, "};\n"); lastfnm = (Symbol *) 0; - lastdef.name = "\"-\""; + lastdef.name = "-"; fprintf(th, "S_F_MAP src_file%d [] = {\n\t", m); for (j = 0, col = 0; j <= n; j++) { lst = (SRC *) 0; @@ -183,8 +187,10 @@ putfnm_flush(j); fprintf(th, "};\n"); - if (m == claimnr) - fprintf(th, "#define src_claim src_ln%d\n", m); + if (pid_is_claim(m) && !did_claim) + { fprintf(th, "short *src_claim;\n"); + did_claim++; + } if (m == eventmapnr) fprintf(th, "#define src_event src_ln%d\n", m); @@ -237,7 +243,27 @@ 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; @@ -349,9 +375,22 @@ 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; --- /sys/src/cmd/spin/pangen3.h Thu Nov 17 15:29:50 2011 +++ /sys/src/cmd/spin/pangen3.h Thu Nov 17 15:29:42 2011 @@ -8,15 +8,16 @@ /* Software written by Gerard J. Holzmann. For tool documentation see: */ /* http://spinroot.com/ */ /* Send all bug-reports and/or questions to: bugs@spinroot.com */ +/* (c) 2007: small additions for V5.0 to support multi-core verifications */ static 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 +38,140 @@ " 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)", */ + + "#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)\n", - "#ifndef VECTORSZ", - "#define VECTORSZ 1024 /* sv size in bytes */", + "#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", 0, }; static 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", "#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", + " #endif", "#else", - "#ifdef BITSTATE", - "#ifdef SAFETY && !defined(HASH64)", - "#define CNTRSTACK", - "#else", - "#define FULLSTACK", - "#endif", - "#else", - "#define FULLSTACK", - "#endif", + " #ifdef BITSTATE", + " #if defined(SAFETY) && !defined(HASH64)", + " #define CNTRSTACK", + " #else", + " #define FULLSTACK", + " #endif", + " #else", + " #define FULLSTACK", + " #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", + " #define HC 0", "#endif", "#ifdef HC1", /* 32+8 bits */ - "#define HC 1", + " #define HC 1", "#endif", "#ifdef HC2", /* 32+16 bits */ - "#define HC 2", + " #define HC 2", "#endif", "#ifdef HC3", /* 32+24 bits */ - "#define HC 3", + " #define HC 3", "#endif", "#ifdef HC4", /* 32+32 bits - combine with -DMA=8 */ - "#define HC 4", + " #define HC 4", "#endif", "#ifdef COLLAPSE", - "unsigned long ncomps[256+2];", + " #if NCORE>1 && !defined(SEP_STATE)", + " unsigned long *ncomps; /* in shared memory */", + " #else", + " unsigned long ncomps[256+2];", + " #endif", "#endif", "#define MAXQ 255", "#define MAXPROC 255", - "#define WS sizeof(long) /* word size in bytes */", - "typedef struct Stack { /* for queues and processes */", + "", + "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;", @@ -159,22 +192,24 @@ " 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];", + + "#ifndef TRIX", + " #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];", "#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 */", + " int vprefix=0, svfd; /* runtime option -pN */", "#endif", "char *tprefix = \"trail\"; /* runtime option -tsuffix */", "short boq = -1; /* blocked_on_queue status */", @@ -214,12 +249,17 @@ "#ifdef HAS_LAST", /* cannot go before _cnt - see hstore() */ " 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", + "#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, }; @@ -235,12 +275,15 @@ " 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, @@ -249,31 +292,46 @@ static char *Addp1[] = { " default: Uerror(\"bad proc - addproc\");", " }", + + "#ifdef TRIX", + " vsize += sizeof(struct 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", + " #ifndef NOCOMP", + " 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", " 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,22 +340,38 @@ " 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", + " #ifndef NOCOMP", + " for (k = 1; k <= Air[n]; k++)", + " Mask[vsize - k] = 1; /* pad */", + " Mask[vsize-j] = 1; /* _pid */", + " #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)", @@ -310,13 +384,16 @@ static 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, }; @@ -324,29 +401,55 @@ static char *Addq1[] = { " default: Uerror(\"bad queue - addqueue\");", " }", + + "#ifdef TRIX", + " vsize += sizeof(struct 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", + " #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", " vsize += (int) q_skip[i];", " q_offset[i] = vsize;", - " now._nr_qs += 1;", " vsize += j;", + "#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", @@ -362,6 +465,19 @@ " 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) {", @@ -509,6 +625,19 @@ " 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);", @@ -547,6 +676,13 @@ "#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, 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", @@ -557,10 +693,11 @@ }; static char *R0[] = { - " Maxbody = max(Maxbody, sizeof(P%d));", + " Maxbody = max(Maxbody, ((int) sizeof(P%d)));", " reached[%d] = reached%d;", " 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));", @@ -572,30 +709,42 @@ }; 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);", - " }", + " retrans(%d, nstates%d, start%d, src_ln%d, reached%d, loopstate%d);", 0, }; static 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, }; @@ -608,17 +757,18 @@ static 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));", + " Maxbody = max(Maxbody, ((int) sizeof(Q%d)));", 0, }; static char *R4[] = { @@ -632,19 +782,22 @@ static 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);", @@ -669,7 +822,7 @@ " if (z) return (long) (x - z);", " return ordinal(scratch, x-scratch, (short) (2+ptr->_t));", "}", - "#endif", + " #endif", "#endif", 0, }; @@ -691,7 +844,7 @@ " if (z) return (long) (x - z);", " return ordinal(scratch, x-scratch, 1); /* chan */", "}", - "#endif", + " #endif", "#endif", 0, }; @@ -709,6 +862,20 @@ "#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;", @@ -725,6 +892,20 @@ "{ 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;", @@ -743,14 +924,14 @@ "char *emalloc(unsigned long);", "char *Malloc(unsigned long);", "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);", @@ -767,16 +948,19 @@ "int unsend(int);", "/* void *sbrk(int); */", "void Uerror(char *);", - "void assert(int, char *, int, int, Trans *);", + "void spin_assert(int, char *, int, int, Trans *);", "void c_chandump(int);", "void c_globals(void);", "void c_locals(int, int);", "void checkcycles(void);", "void crack(int, int, Trans *, short *);", + "void d_sfh(const char *, int);", + "void sfh(const char *, int);", "void d_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);", @@ -787,28 +971,29 @@ "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 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 do_dfs(int, int, int, short *, uchar *, uchar *);", "void uerror(char *);", "void unrecv(int, int, int, int, int);", "void usage(FILE *);", "void wrap_stats(void);", "#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", 0, }; @@ -825,6 +1010,35 @@ "#ifdef NOVSZ", " strcat(ctd, \"-DNOVSZ \");", "#endif", + "#ifdef REVERSE", + " strcat(ctd, \"-DREVERSE \");", + "#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);", @@ -888,6 +1102,9 @@ "#ifdef CTL", " strcat(ctd, \"-DCTL \");", "#endif", + "#ifdef TRIX", + " strcat(ctd, \"-DTRIX \");", + "#endif", "#ifdef NIBIS", " strcat(ctd, \"-DNIBIS \");", "#endif", @@ -916,7 +1133,7 @@ "#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 +1148,35 @@ "#ifdef SDUMP", " strcat(ctd, \"-DSDUMP \");", "#endif", - "#ifdef COVEST", - " strcat(ctd, \"-DCOVEST \");", + "#if NCORE>1", + " sprintf(carg, \"-DNCORE=%%d \", NCORE);", + " strcat(ctd, carg);", + "#endif", + "#ifdef SFH", + " sprintf(carg, \"-DSFH \");", + " 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);", "}", --- /sys/src/cmd/spin/pangen4.c Thu Nov 17 15:30:00 2011 +++ /sys/src/cmd/spin/pangen4.c Thu Nov 17 15:29:54 2011 @@ -307,6 +307,8 @@ ntimes(tc, 0, 1, R15); } +extern void explain(int); + int proper_enabler(Lextok *n) { @@ -321,7 +323,9 @@ return 1; return (!(n->sym->context)); - case CONST: case TIMEOUT: + case C_EXPR: + case CONST: + case TIMEOUT: has_provided = 1; return 1; @@ -340,5 +344,8 @@ default: break; } + printf("spin: saw "); + explain(n->ntyp); + printf("\n"); return 0; } --- /sys/src/cmd/spin/pangen5.c Thu Nov 17 15:30:27 2011 +++ /sys/src/cmd/spin/pangen5.c Thu Nov 17 15:30:20 2011 @@ -211,13 +211,18 @@ 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 +239,7 @@ 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 +260,7 @@ } 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 +284,14 @@ 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); @@ -346,9 +349,8 @@ #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"); @@ -679,7 +681,8 @@ 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 +695,7 @@ 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 +711,7 @@ { 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 +726,7 @@ { 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 +734,7 @@ } if (export_ast) { AST_slice(); - exit(0); + alldone(0); /* changed in 5.3.0: was exit(0) */ } } --- /sys/src/cmd/spin/pangen5.h Thu Nov 17 15:30:39 2011 +++ /sys/src/cmd/spin/pangen5.h Thu Nov 17 15:30:32 2011 @@ -80,7 +80,7 @@ " 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;", @@ -372,7 +372,7 @@ " 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\");", "", --- /sys/src/cmd/spin/pangen6.c Thu Nov 17 15:31:01 2011 +++ /sys/src/cmd/spin/pangen6.c Thu Nov 17 15:30:47 2011 @@ -90,7 +90,6 @@ 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 +144,7 @@ { 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 */ @@ -503,7 +502,7 @@ 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 +544,14 @@ 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 +691,7 @@ } 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 +783,8 @@ */ 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 +818,9 @@ 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); @@ -1075,7 +1070,7 @@ case NAME: name_AST_track(now, code); - if (now->sym->nel != 1) + if (now->sym->nel > 1 || now->sym->isarray) AST_track(now->lft, USE|code); /* index */ break; @@ -1569,7 +1564,8 @@ { 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 +1597,8 @@ 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 +1618,9 @@ { 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 +1630,7 @@ 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 +1686,7 @@ 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 +1723,7 @@ 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 +1800,10 @@ 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 +1834,8 @@ } } 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 @@ -2261,6 +2249,7 @@ FSM_trans *t; AST *a; int oi; + static FSM_state no_state; #if 0 find dominators Aho, Sethi, & Ullman, Compilers - principles, techniques, and tools --- /sys/src/cmd/spin/pangen6.h Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/spin/pangen6.h Thu Nov 17 15:31:13 2011 @@ -0,0 +1,2840 @@ +/***** spin: pangen6.h *****/ + +/* Copyright (c) 2006-2007 by the California Institute of Technology. */ +/* ALL RIGHTS RESERVED. United States Government Sponsorship acknowledged */ +/* Supporting routines for a multi-core extension of the SPIN software */ +/* Developed as part of Reliable Software Engineering Project ESAS/6G */ +/* Like all SPIN Software 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. */ +/* Any commercial use must be negotiated with the Office of Technology */ +/* Transfer at the California Institute of Technology. */ +/* Software written by Gerard J. Holzmann. For tool documentation see: */ +/* http://spinroot.com/ */ +/* Bug-reports and/or questions can be send to: bugs@spinroot.com */ + +static 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 usefule -- 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];", + " volatile char m_Mask [(VMAX + 7)/8];", + " 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 *);", + "#if 0", + "void enter_critical(int);", + "void leave_critical(int);", + "#endif", + "", + "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, *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 */", + " {", + "#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\",", + " worker_pids[i], (dwExitCode == STILL_ACTIVE));", + "#else", + " sprintf(b, \"kill -%%d %%d\", SIGKILL, worker_pids[i]);", + " 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 */ + " { sprintf(b, \"kill -%%d %%d\", SIGINT, worker_pids[0]);", + " 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;", + "", + "struct 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 %%d)\\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;", + " 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 = (struct 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 = (struct 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 */ + "}", + "", + " /* 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;", + " }", + " #else", + " #error missing definition of test and set operation for this platform", + " #endif", + "", + "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 BFS is not supported with multi-core", + "#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", + "", + "struct 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 (struct 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 (struct H_el *) rval;", + "#else", + " return (struct 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 struct 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);", + " 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);", + " 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);", + " 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 = (struct 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 = (struct 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 BFS is not supported in multi-core mode", + "#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, +}; --- /sys/src/cmd/spin/pangen7.c Thu Jan 1 00:00:00 1970 +++ /sys/src/cmd/spin/pangen7.c Thu Nov 17 15:31:18 2011 @@ -0,0 +1,925 @@ +/***** spin: pangen7.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 */ +/* pangen7.c: Version 5.3.0 2010, synchronous product of never claims */ + +#include +#include "spin.h" +#include "y.tab.h" +#include +#ifdef PC +extern int unlink(const char *); +#else +#include +#endif + +extern ProcList *rdy; +extern Element *Al_El; +extern int nclaims, verbose, Strict; + +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; +}; + +SQueue *sq, *sd, *render; /* states move from sq to sd to render to holding */ +SQueue *holding, *lasthold; +State_Stack *dsts; + +int nst; /* max nr of states in claims */ +int *Ist; /* initial states */ +int *Nacc; /* number of accept states in claim */ +int *Nst; /* next states */ +int **reached; /* n claims x states */ +int unfolding; /* to make sure all accept states are reached */ +int is_accept; /* remember if the current state is accepting in any claim */ +int not_printing; /* set during explore_product */ + +Element ****matrix; /* n x two-dimensional arrays state x state */ +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); + comment(stdout, t, 0); + printf(post); +} + +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); + 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); + 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; + + 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 + { 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); + 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; + } + 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; + } +} --- /sys/src/cmd/spin/pc_zpp.c Thu Nov 17 15:31:28 2011 +++ /sys/src/cmd/spin/pc_zpp.c Thu Nov 17 15:31:22 2011 @@ -16,14 +16,15 @@ #include #include #include +#include "spin.h" #ifdef PC enum cstate { PLAIN, IN_STRING, IN_QUOTE, S_COMM, COMMENT, E_COMM }; #define MAXNEST 32 #define MAXDEF 128 -#define MAXLINE 512 -#define GENEROUS 4096 +#define MAXLINE 2048 +#define GENEROUS 8192 #define debug(x,y) if (verbose) printf(x,y) @@ -43,7 +44,7 @@ static int process(char *, int, char *); static int zpp_do(char *); -extern char *emalloc(int); /* main.c */ +extern char *emalloc(size_t); /* main.c */ static int do_define(char *p) @@ -116,7 +117,7 @@ if (strlen(in1)+strlen(d[i].trg)+strlen(in2+j) >= GENEROUS) { - printf("spin: circular macro expansion %s -> %s ?\n", + printf("spin: macro expansion overflow %s -> %s ?\n", d[i].src, d[i].trg); return in1; } @@ -230,8 +231,9 @@ } static int -do_else(char *unused) +do_else(char *p) { + debug("zpp: do_else %s", p); if_truth[if_depth] = 1-if_truth[if_depth]; printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth]; @@ -312,13 +314,29 @@ } static int +strip_cpp_comments(char *p) +{ char *q; + + q = strstr(p, "//"); + if (q) + { if (q > p && *(q-1) == '\\') + { return strip_cpp_comments(q+1); + } + *q = '\n'; + *(q+1) = '\0'; + return 1; + } + return 0; +} + +static int zpp_do(char *fnm) { char buf[2048], buf2[MAXLINE], *p; int n, on; FILE *inp; int lno = 0, nw_lno = 0; if ((inp = fopen(fnm, "r")) == NULL) - { fprintf(stdout, "spin: error, '%s': No such file\n", fnm); - return 0; /* 4.1.2 was stderr */ + { fprintf(stdout, "spin: error: No file '%s'\n", fnm); + exit(1); /* 4.1.2 was stderr */ } printing[0] = if_truth[0] = 1; fprintf(outpp, "#line %d \"%s\"\n", lno+1, fnm); @@ -327,7 +345,8 @@ on = 0; nw_lno = 0; while (n > 2 && buf[n-2] == '\\') { buf[n-2] = '\0'; -feedme: if (!fgets(buf2, MAXLINE, inp)) +feedme: + if (!fgets(buf2, MAXLINE, inp)) { debug("zpp: unexpected EOF ln %d\n", lno); return 0; /* switch to cpp */ } @@ -339,6 +358,10 @@ strcat(buf, buf2); n = (int) strlen(buf); } + + if (strip_cpp_comments(&buf[on])) + n = (int) strlen(buf); + if (in_comment(&buf[on])) { buf[n-1] = '\0'; /* eat newline */ on = n-1; nw_lno = 1; @@ -360,7 +383,7 @@ int try_zpp(char *fnm, char *onm) { int r; - if ((outpp = fopen(onm, "w")) == NULL) + if ((outpp = fopen(onm, MFLAGS)) == NULL) return 0; r = zpp_do(fnm); fclose(outpp); @@ -390,6 +413,27 @@ for (p = q; *p; p++) if (*p != ' ' && *p != '\t') break; + + if (strncmp(p, "line", 4) == 0) + { p += 4; + while (*p == ' ' || *p == '\t') + { p++; + } + lno = atoi(p); + return 1; /* line directive */ + } + if (isdigit((int) *p)) + { lno = atoi(p); + return 1; + } + if (strncmp(p, "error", 5) == 0) + { printf("spin: %s", p); + exit(1); + } + if (strncmp(p, "warning", 7) == 0) + { printf("spin: %s", p); + return 1; + } for (i = 0; i < (int) (sizeof(s)/sizeof(struct Directives)); i++) if (!strncmp(s[i].directive, p, s[i].len)) { if (s[i].interp --- /sys/src/cmd/spin/ps_msc.c Thu Nov 17 15:31:39 2011 +++ /sys/src/cmd/spin/ps_msc.c Thu Nov 17 15:31:33 2011 @@ -12,14 +12,12 @@ /* The Postscript generation code below was written by Gerard J. Holzmann */ /* in June 1997. Parts of the prolog template are based on similar boiler */ /* plate in the Tcl/Tk distribution. This code is used to support Spin's */ -/* option M for generating a Postscript file from a simulation run. */ +/* option -M for generating a Postscript file from a simulation run. */ #include "spin.h" #include "version.h" -#ifdef PC -extern void free(void *); -#endif +/* extern void free(void *); */ static char *PsPre[] = { "%%%%Pages: (atend)", @@ -110,8 +108,8 @@ 0, }; -int MH = 600; /* page height - can be scaled */ -int oMH = 600; /* page height - not scaled */ +static int MH = 600; /* page height - can be scaled */ +static int oMH = 600; /* page height - not scaled */ #define MW 500 /* page width */ #define LH 100 /* bottom margin */ #define RH 100 /* right margin */ @@ -146,7 +144,7 @@ fprintf(pfd, "0.000 0.000 0.000 setrgbcolor AdjustColor\n"); fprintf(pfd, "%d %d [\n", MW/2, LH+oMH+ 5*HH); fprintf(pfd, " (%s -- %s -- MSC -- %d)\n] 10 -0.5 0.5 0 ", - Version, oFname?oFname->name:"", pspno); + SpinVersion, oFname?oFname->name:"", pspno); fprintf(pfd, "false DrawText\ngrestore\n"); } @@ -181,11 +179,11 @@ { char snap[256]; FILE *fd; sprintf(snap, "%s.ps", oFname?oFname->name:"msc"); - if (!(pfd = fopen(snap, "w"))) + if (!(pfd = fopen(snap, MFLAGS))) fatal("cannot create file '%s'", snap); fprintf(pfd, "%%!PS-Adobe-2.0\n"); - fprintf(pfd, "%%%%Creator: %s\n", Version); + fprintf(pfd, "%%%%Creator: %s\n", SpinVersion); fprintf(pfd, "%%%%Title: MSC %s\n", oFname?oFname->name:"--"); fprintf(pfd, "%%%%BoundingBox: 119 154 494 638\n"); ntimes(pfd, 0, 1, PsPre); @@ -204,6 +202,7 @@ while (fgets(snap, 256, fd)) TotSteps++; fclose(fd); } + TotSteps += 10; R = (int *) emalloc(TotSteps * sizeof(int)); D = (int *) emalloc(TotSteps * sizeof(int)); M = (short *) emalloc(TotSteps * sizeof(short)); @@ -227,6 +226,7 @@ pspno, oFname?oFname->name:"msc"); exit(0); } + void psline(int x0, int iy0, int x1, int iy1, float r, float g, float b, int w) { int y0 = MH-iy0; @@ -260,11 +260,10 @@ { int i; for (i = p ; i >= 0; i--) - if (!ProcLine[i]) - { psline(i,0, i,MH-1, - (float) 0.4, (float) 0.4, (float) 1.0, 1); + { if (!ProcLine[i]) + { psline(i, 0, i, MH-1, (float) (0.4), (float) (0.4), (float) (1.0), 1); ProcLine[i] = 1; - } + } } } void @@ -320,7 +319,7 @@ } else { r = (float) 1.; g = (float) 1.; b = (float) 0.; if (!dx - && sscanf(s, "%d:%s", &a, d) == 2 /* was &d */ + && sscanf(s, "%d:%250s", &a, d) == 2 /* was &d */ && a >= 0 && a < TotSteps) { if (!I[a] || strlen(I[a]) <= strlen(s)) @@ -386,7 +385,7 @@ } if (L[i]) { spitbox(M[i], 0, i, L[i]); - free(L[i]); + /* free(L[i]); */ lasti = i; } } @@ -397,10 +396,9 @@ putbox(int x) { if (ldepth >= TotSteps) - { putpostlude(); - fprintf(stderr, "max length of %d steps exceeded\n", + { fprintf(stderr, "max length of %d steps exceeded - ps file truncated\n", TotSteps); - fatal("postscript file truncated", (char *) 0); + putpostlude(); } M[ldepth] = x; if (x > maxx) maxx = x; --- /sys/src/cmd/spin/reprosrc.c Thu Nov 17 15:31:47 2011 +++ /sys/src/cmd/spin/reprosrc.c Thu Nov 17 15:31:43 2011 @@ -96,7 +96,7 @@ 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 { "); --- /sys/src/cmd/spin/run.c Thu Nov 17 15:31:58 2011 +++ /sys/src/cmd/spin/run.c Thu Nov 17 15:31:52 2011 @@ -18,7 +18,7 @@ extern Element *LastStep; extern int Rvous, lineno, Tval, interactive, MadeChoice; 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; static long Seed = 1; static int E_Check = 0, Escape_Check = 0; @@ -57,9 +57,9 @@ 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 +69,13 @@ #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 +85,7 @@ { 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 +95,10 @@ { 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 +121,21 @@ 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 +148,11 @@ 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 +174,7 @@ else k = Rand()%j; /* nondeterminism */ } + has_else = ZE; bas_else = ZE; for (i = 0, z = e->sub; i < j+k; i++) @@ -234,6 +254,9 @@ 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) @@ -246,7 +269,11 @@ { 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; } } } @@ -386,13 +413,17 @@ case PRINTM: return TstOnly?1:printm(stdout, now); case ASGN: return assign(now); - case C_CODE: printf("%s:\t", now->sym->name); - plunk_inline(stdout, now->sym->name, 0); + 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; @@ -426,7 +457,6 @@ j = n->lft->val; else j = eval(n->lft); - Buf[0] = '\0'; sr_buf(j, 1); dotag(fd, Buf); } @@ -437,9 +467,9 @@ 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 +520,7 @@ } 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; } @@ -600,3 +630,4 @@ } return result; } + --- /sys/src/cmd/spin/sched.c Thu Nov 17 15:32:13 2011 +++ /sys/src/cmd/spin/sched.c Thu Nov 17 15:32:03 2011 @@ -20,7 +20,7 @@ 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 int limited_vis, old_scope_rules, product, nclaims; RunList *X = (RunList *) 0; RunList *run = (RunList *) 0; @@ -42,13 +42,16 @@ r->n = p->n; r->tn = p->tn; + r->b = p->b; r->pid = nproc++ - nstop + Skip_claim; - 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\n", + p->n?p->n->name:"--", r->pid); 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; @@ -59,13 +62,15 @@ r->nxt = run; r->prov = p->prov; r->priority = weight; + 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,8 +78,12 @@ r->n = n; r->p = p; r->s = s; + r->b = b; r->prov = prov; r->tn = nrRdy++; + if (det != 0 && det != 1) + { fprintf(stderr, "spin: bad value for det (cannot happen)\n"); + } r->det = (short) det; r->nxt = rdy; rdy = r; @@ -135,6 +144,7 @@ if (dumptab || analyze + || product || s_trail || !(verbose&4)) return; @@ -208,26 +218,29 @@ 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 */ @@ -457,9 +470,12 @@ } 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') @@ -484,6 +500,24 @@ } 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 -N name (defaults to -N %s)\n", + q?q->n->name:"--"); + } +} + +void sched(void) { Element *e; RunList *Y = NULL; /* previous process in run queue */ @@ -504,10 +538,16 @@ printf("models with synchronous channels.\n"); nr_errs++; } + if (product) + { sync_product(); + alldone(0); + } if (analyze) { gensrc(); + multi_claims(); return; - } else if (s_trail) + } + if (s_trail) { match_trail(); return; } @@ -543,7 +583,7 @@ depth++; LastStep = ZE; oX = X; /* a rendezvous could change it */ go = 1; - if (X && X->prov && X->pc + if (X->prov && X->pc && !(X->pc->status & D_ATOM) && !eval(X->prov)) { if (!xspin && ((verbose&32) || (verbose&4))) @@ -570,7 +610,8 @@ 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 +628,12 @@ } } 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; @@ -618,6 +661,9 @@ dotag(stdout, "timeout\n"); X = oX; } } } } + + if (!run || !X) break; /* new 5.0 */ + Y = pickproc(X); notbeyond = 0; } @@ -692,7 +738,9 @@ 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)); @@ -704,13 +752,18 @@ 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 +812,7 @@ 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 +821,7 @@ 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,7 +862,8 @@ return ZS; } for (r = X->symtab; r; r = r->next) - if (strcmp(r->name, s->name) == 0) + 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); @@ -895,6 +949,7 @@ void p_talk(Element *e, int lnr) { static int lastnever = -1; + static char nbuf[128]; int newnever = -1; if (e && e->n) @@ -918,9 +973,22 @@ 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 */ @@ -978,7 +1046,7 @@ 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) --- /sys/src/cmd/spin/spin.h Thu Nov 17 15:32:24 2011 +++ /sys/src/cmd/spin/spin.h Thu Nov 17 15:32:18 2011 @@ -1,6 +1,6 @@ /***** spin: spin.h *****/ -/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ +/* Copyright (c) 1989-2009 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 */ @@ -16,12 +16,16 @@ #include #include +enum { INIV, PUTV, LOGV }; /* for pangen[14].c */ +enum btypes { NONE, N_CLAIM, I_PROC, A_PROC, P_PROC, E_TRACE, N_TRACE }; + typedef struct Lextok { unsigned short ntyp; /* node type */ short ismtyp; /* CONST derived from MTYP */ 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 +58,8 @@ 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 nbits; /* optional width specifier */ int nel; /* 1 if scalar, >1 if array */ int setat; /* last depth value changed */ @@ -124,7 +130,7 @@ 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 */ @@ -148,6 +154,7 @@ 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; @@ -162,6 +169,7 @@ 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,8 +182,10 @@ 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 */ struct ProcList *nxt; /* linked list */ } ProcList; @@ -194,7 +204,8 @@ #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,12 +227,17 @@ #define SOMETHINGBIG 65536 #define RATHERSMALL 512 +#define MAXSCOPESZ 1024 #ifndef max #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 *); @@ -239,7 +255,7 @@ Lextok *rem_var(Symbol *, Lextok *, Symbol *, Lextok *); Lextok *tail_add(Lextok *, 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 +266,7 @@ Symbol *lookup(char *); Symbol *prep_inline(Symbol *, Lextok *); -char *emalloc(int); +char *emalloc(size_t); long Rand(void); int any_oper(Lextok *, int); @@ -274,12 +290,14 @@ 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 *); @@ -321,6 +339,7 @@ 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 *); @@ -355,7 +374,7 @@ 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 prune_opts(Lextok *); @@ -378,15 +397,17 @@ void setuname(Lextok *); void setutype(Lextok *, Symbol *, Lextok *); void setxus(Lextok *, int); +void show_lab(void); void Srand(unsigned); 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); --- /sys/src/cmd/spin/spin.y Thu Nov 17 15:32:38 2011 +++ /sys/src/cmd/spin/spin.y Thu Nov 17 15:32:30 2011 @@ -11,26 +11,44 @@ %{ #include "spin.h" +#include +#ifndef PC +#include +#endif #include #define YYDEBUG 0 #define Stop nn(ZN,'@',ZN,ZN) +#define PART0 "place initialized var decl 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 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 int u_sync, u_async, dumptab, scope_level; +extern int initialization_ok, split_decl; extern short has_sorted, has_random, has_enabled, has_pcvalue, has_np; extern short has_code, has_state, has_io; extern void count_runs(Lextok *); extern void no_internals(Lextok *); extern void any_runs(Lextok *); +extern void ltl_list(char *, char *); extern void validref(Lextok *, 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; char *claimproc = (char *) 0; char *eventmap = (char *) 0; +static char *ltl_name; static int Embedded = 0, inEventMap = 0, has_ini = 0; @@ -41,7 +59,7 @@ %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 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 +68,16 @@ %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,6 +103,7 @@ unit : proc /* proctype { } */ | init /* init { } */ | claim /* never claim */ + | ltl /* ltl formula */ | events /* event assertions */ | one_decl /* variables, chans */ | utype /* user defined types */ @@ -91,7 +114,7 @@ ; proc : inst /* optional instantiator */ - proctype NAME { + proctype NAME { setptype($3, PROCTYPE, ZN); setpname($3); context = $3->sym; @@ -106,13 +129,22 @@ 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; } @@ -133,10 +165,10 @@ $$ = 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,30 +178,68 @@ 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; + } + ; + +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--; } @@ -252,7 +322,12 @@ body : '{' { open_seq(1); } sequence OS { add_seq(Stop); } - '}' { $$->sq = close_seq(0); } + '}' { $$->sq = close_seq(0); + if (scope_level != 0) + { non_fatal("missing '}' ?", 0); + scope_level = 0; + } + } ; sequence: step { if ($1) add_seq($1); } @@ -277,7 +352,9 @@ | 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); } @@ -314,17 +391,34 @@ $1->sym->ini = nn(ZN,CONST,ZN,ZN); $1->sym->ini->val = 0; } - | vardcl ASGN expr { $1->sym->ini = $3; $$ = $1; - trackvar($1,$3); has_ini = 1; + | vardcl ASGN expr { $$ = $1; + $1->sym->ini = $3; + trackvar($1,$3); + if ($3->ntyp == CONST + || ($3->ntyp == NAME && $3->sym->context)) + { has_ini = 2; /* local init */ + } else + { has_ini = 1; /* possibly global */ + } + if (!initialization_ok && split_decl) + { nochan_manip($1, $3, 0); + no_internals($1); + non_fatal(PART0 "'%s'" PART2, $1->sym->name); + } } | vardcl ASGN ch_init { $1->sym->ini = $3; $$ = $1; has_ini = 1; + if (!initialization_ok && split_decl) + { non_fatal(PART1 "'%s'" PART2, $1->sym->name); + } } ; ch_init : '[' CONST ']' OF - '{' typ_list '}' { if ($2->val) u_async++; - else u_sync++; + '{' typ_list '}' { if ($2->val) + u_async++; + else + u_sync++; { int i = cnt_mpars($6); Mpars = max(Mpars, i); } @@ -342,13 +436,18 @@ } $1->sym->nel = 1; $$ = $1; } - | NAME '[' CONST ']' { $1->sym->nel = $3->val; $$ = $1; } + | NAME '[' CONST ']' { $1->sym->nel = $3->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 +462,7 @@ 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 +473,19 @@ | '.' cmpnd %prec DOT { $$ = nn(ZN, '.', $2, ZN); } ; -stmnt : Special { $$ = $1; } - | Stmnt { $$ = $1; +stmnt : Special { $$ = $1; initialization_ok = 0; } + | Stmnt { $$ = $1; initialization_ok = 0; if (inEventMap) non_fatal("not an event", (char *)0); } ; +for_pre : FOR '(' { in_for = 1; } + varref { $$ = $4; } + ; + +for_post: '{' sequence OS '}' ; + Special : varref RCV { Expand_Ok++; } rargs { Expand_Ok--; has_io++; $$ = nn($1, 'r', $1, $4); @@ -392,6 +497,18 @@ $$->val=0; trackchanuse($4, ZN, 'S'); any_runs($4); } + | for_pre ':' expr DOTDOT expr ')' { + for_setup($1, $3, $5); in_for = 0; + } + for_post { $$ = for_body($1, 1); + } + | for_pre IN varref ')' { $$ = for_index($1, $3); in_for = 0; + } + for_post { $$ = for_body($5, 1); + } + | SELECT '(' varref ':' expr DOTDOT expr ')' { + $$ = sel_index($3, $5, $7); + } | IF options FI { $$ = nn($1, IF, ZN, ZN); $$->sl = $2->sl; prune_opts($$); @@ -422,7 +539,7 @@ } ; -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); @@ -482,7 +599,9 @@ $$->sl = seqlist(close_seq(3), 0); 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); make_atomic($$->sl->this, D_ATOM); @@ -548,10 +667,8 @@ | 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 ')' Opt_priority { Expand_Ok--; @@ -572,7 +689,7 @@ $$ = 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; @@ -591,6 +708,7 @@ { $$ = 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; } ; Opt_priority: /* none */ { $$ = ZN; } @@ -598,21 +716,22 @@ ; full_expr: expr { $$ = $1; } - | Expr { $$ = $1; } + | Expr { $$ = $1; } ; -Opt_enabler: /* none */ { $$ = ZN; } - | PROVIDED '(' full_expr ')' { if (!proper_enabler($3)) - { non_fatal("invalid PROVIDED clause", - (char *)0); - $$ = ZN; - } else - $$ = $3; - } - | PROVIDED error { $$ = ZN; - non_fatal("usage: provided ( ..expr.. )", - (char *)0); - } +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 */ @@ -620,9 +739,9 @@ | '(' Expr ')' { $$ = $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 AND Expr { $$ = nn(ZN, AND, $1, $3); } | expr OR Expr { $$ = nn(ZN, OR, $1, $3); } ; @@ -632,6 +751,20 @@ | NEMPTY '(' varref ')' { $$ = nn($3,NEMPTY, $3, ZN); } ; +Opt_enabler: /* none */ { $$ = ZN; } + | PROVIDED '(' full_expr ')' { if (!proper_enabler($3)) + { non_fatal("invalid PROVIDED clause", + (char *)0); + $$ = ZN; + } else + $$ = $3; + } + | PROVIDED error { $$ = ZN; + non_fatal("usage: provided ( ..expr.. )", + (char *)0); + } + ; + basetype: TYPE { $$->sym = ZS; $$->val = $1->val; if ($$->val == UNSIGNED) @@ -676,9 +809,9 @@ ; rarg : varref { $$ = $1; trackvar($1, $1); - trapwonly($1, "rarg"); } + trapwonly($1 /*, "rarg" */); } | EVAL '(' expr ')' { $$ = nn(ZN,EVAL,$3,ZN); - trapwonly($1, "eval rarg"); } + trapwonly($1 /*, "eval rarg" */); } | CONST { $$ = nn(ZN,CONST,ZN,ZN); $$->ismtyp = $1->ismtyp; $$->val = $1->val; @@ -714,6 +847,98 @@ | nlst ',' { $$ = $1; /* commas optional */ } ; %% + +#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; + default: + comment(fd, n, 0); + break; + } +} + +#define TMP_FILE "_S_p_I_n_.tmp" + +extern int unlink(const char *); + +static Lextok * +ltl_to_string(Lextok *n) +{ Lextok *m = nn(ZN, 0, ZN, ZN); + char *retval; + char formula[1024]; + FILE *tf = fopen(TMP_FILE, "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); + } + recursive(tf, n); + (void) fseek(tf, 0L, SEEK_SET); + + memset(formula, 0, sizeof(formula)); + retval = fgets(formula, sizeof(formula), tf); + fclose(tf); + (void) unlink(TMP_FILE); + + if (!retval) + { printf("%p\n", retval); + fatal("could not translate ltl formula", 0); + } + + if (1) printf("ltl %s: %s\n", ltl_name, formula); + + m->sym = lookup(formula); + + return m; +} void yyerror(char *fmt, ...) --- /sys/src/cmd/spin/spinlex.c Thu Nov 17 15:32:56 2011 +++ /sys/src/cmd/spin/spinlex.c Thu Nov 17 15:32:45 2011 @@ -23,6 +23,7 @@ Lextok *params; /* formal pars if any */ char **anms; /* literal text for actual pars */ char *prec; /* precondition for c_code or c_expr */ + int uiid; /* unique inline id */ int dln, cln; /* def and call linenr */ Symbol *dfn, *cfn; /* def and call filename */ struct IType *nxt; /* linked list */ @@ -37,14 +38,16 @@ 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 int verbose, IArgs, hastrack, separate, ltl_mode; short has_stack = 0; int lineno = 1; +int scope_seq[128], scope_level = 0; +char CurScope[MAXSCOPESZ]; char yytext[2048]; FILE *yyin, *yyout; @@ -81,20 +84,23 @@ #if 1 #define Getchar() ((Inlining<0)?getc(yyin):getinline()) -#define Ungetch(c) {if (Inlining<0) ungetc(c,yyin); else uninline(); } +#define Ungetch(c) {if (Inlining<0) ungetc(c,yyin); else uninline();} #else static int Getchar(void) { int c; + if (Inlining<0) c = getc(yyin); else c = getinline(); -#if 1 - printf("<%c>", c); -#endif + if (0) + { printf("<%c:%d>[%d] ", c, c, Inlining); + } else + { printf("%c", c); + } return c; } @@ -105,13 +111,18 @@ ungetc(c,yyin); else uninline(); -#if 1 - printf(""); -#endif + if (0) + { printf(""); + } } #endif static int +notdollar(int c) +{ return (c != '$' && c != '\n'); +} + +static int notquote(int c) { return (c != '\"' && c != '\n'); } @@ -133,14 +144,15 @@ 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); } @@ -161,10 +173,11 @@ 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 +192,12 @@ 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; } @@ -269,8 +283,8 @@ 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 +300,16 @@ 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 +319,7 @@ break; if (!tmp) fatal("cannot happen, missing inline def %s", s); + return tmp; } @@ -329,7 +354,7 @@ && strcmp(stackonly->name, "\"StackOnly\"") != 0) non_fatal("expecting '[Un]Matched', saw %s", stackonly->name); else - has_stack = 1; + has_stack = 1; /* unmatched stack */ } } @@ -514,32 +539,38 @@ } void -c_add_stack(FILE *fd) +c_stack_size(FILE *fd) { C_Added *r; int cnt = 0; - if ((!c_added && !c_tracked) || !has_stack) return; - - for (r = c_tracked; r; r = r->nxt) if (r->ival != ZS) + { fprintf(fd, "%s%s", + (cnt==0)?"":"+", r->t->name); cnt++; + } + if (cnt == 0) + { fprintf(fd, "WS"); + } +} - if (cnt == 0) return; +void +c_add_stack(FILE *fd) +{ C_Added *r; + int cnt = 0; - fprintf(fd, " uchar c_stack["); + if ((!c_added && !c_tracked) || !has_stack) + { return; + } - cnt = 0; for (r = c_tracked; r; r = r->nxt) - { if (r->ival == ZS) continue; + if (r->ival != ZS) + { cnt++; + } - 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 @@ -610,9 +641,10 @@ } 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; @@ -660,7 +692,7 @@ 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; @@ -792,7 +824,7 @@ 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, "trpt->st = tt; uerror(\"%s\"); continue; } ", tmp->prec); fprintf(fd, "else { printf(\"pan: precondition false: %s\\n\"); ", tmp->prec); fprintf(fd, "_m = 3; goto P999; } } \n\t\t"); } @@ -814,7 +846,7 @@ } void -plunk_inline(FILE *fd, char *s, int how) /* c_code with precondition */ +plunk_inline(FILE *fd, char *s, int how, int gencode) /* c_code with precondition */ { IType *tmp; tmp = find_inline(s); @@ -822,12 +854,19 @@ 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(\"%s\"); continue; ", + 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"); } @@ -875,8 +914,7 @@ 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 */ @@ -887,7 +925,7 @@ 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,8 +935,8 @@ 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]) @@ -930,13 +968,15 @@ 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 +1005,43 @@ 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; - 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 +1059,20 @@ 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, ""); + 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': @@ -1046,8 +1089,8 @@ { *p = '\0'; if (s->type == CODE_FRAG) *--p = '\0'; /* remove trailing '}' */ - def_inline(s, dln, &buf[0], &buf2[0], nms); - if (firstchar && s) + 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 */ @@ -1057,19 +1100,38 @@ 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; + 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 lex(void) { int c; @@ -1079,6 +1141,8 @@ yytext[0] = (char) c; yytext[1] = '\0'; switch (c) { + case EOF: + return c; case '\n': /* newline */ lineno++; case '\r': /* carriage return */ @@ -1099,6 +1163,13 @@ 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 == '\\') @@ -1131,6 +1202,26 @@ 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; } @@ -1149,12 +1240,35 @@ 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) } 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[] = { {"active", ACTIVE, 0, 0}, @@ -1178,14 +1292,18 @@ {"eval", EVAL, 0, 0}, {"false", CONST, 0, 0}, {"fi", FI, 0, 0}, + {"for", FOR, 0, 0}, {"full", FULL, 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:"}, @@ -1203,7 +1321,7 @@ {"provided", PROVIDED, 0, 0}, {"run", RUN, 0, 0}, {"d_step", D_STEP, 0, 0}, - {"inline", INLINE, 0, 0}, + {"select", SELECT, 0, 0}, {"short", TYPE, SHORT, 0}, {"skip", CONST, 1, 0}, {"timeout", TIMEOUT, 0, 0}, @@ -1223,13 +1341,20 @@ { 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); return Names[i].tok; - } + } } if ((yylval->val = ismtype(s)) != 0) { yylval->ismtyp = 1; @@ -1253,19 +1378,29 @@ 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; } } @@ -1353,6 +1488,9 @@ } else if (c == CONST && yytext[0] == '\'') { sprintf(yytext, "'%c'", yylval->val); strcat(IArg_cont[IArgno], yytext); + } else if (c == CONST) + { sprintf(yytext, "%d", yylval->val); + strcat(IArg_cont[IArgno], yytext); } else { switch (c) { @@ -1379,6 +1517,5 @@ strcat(IArg_cont[IArgno], yytext); } } - return c; } --- /sys/src/cmd/spin/structs.c Thu Nov 17 15:33:07 2011 +++ /sys/src/cmd/spin/structs.c Thu Nov 17 15:33:01 2011 @@ -19,7 +19,7 @@ } UType; extern Symbol *Fname; -extern int lineno, depth, Expand_Ok; +extern int lineno, depth, Expand_Ok, has_hidden, in_for; Symbol *owner; @@ -33,14 +33,16 @@ 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 +104,22 @@ { 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 +199,7 @@ 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 +226,12 @@ 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 +252,7 @@ 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 +272,9 @@ 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 +321,7 @@ 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 +360,7 @@ 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 +398,7 @@ } 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 +412,10 @@ 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 +433,10 @@ 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 +450,7 @@ 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 +459,7 @@ 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 +483,7 @@ 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 +491,7 @@ for (fp = z->Sval[ix]; fp; fp = fp->rgt) for (tl = fp->lft; tl; tl = tl->rgt) { if (tl->sym->type == STRUCT) - { char pref[256]; + { char pref[300]; strcpy(pref, eprefix); strcat(pref, "."); strcat(pref, tl->sym->name); @@ -498,7 +505,7 @@ 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,8 +586,10 @@ int i, cnt; extern int IArgs; if (n->sym->type != STRUCT + || in_for || is_explicit(n)) return n; + if (n->rgt && n->rgt->ntyp == '.' --- /sys/src/cmd/spin/sym.c Thu Nov 17 15:33:18 2011 +++ /sys/src/cmd/spin/sym.c Thu Nov 17 15:33:12 2011 @@ -14,14 +14,19 @@ 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; + static Ordered *last_name = (Ordered *)0; static Symbol *symtab[Nhash+1]; +static Lextok *runstmnts = ZN; static int samename(Symbol *a, Symbol *b) @@ -44,31 +49,77 @@ return h&Nhash; } +void +disambiguate(void) +{ Ordered *walk; + Symbol *sp; + + if (old_scope_rules) + return; + + /* if the same name appears in two different scopes, + 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) + { char *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; /* discord the old memory */ + } } +} + Symbol * lookup(char *s) { Symbol *sp; Ordered *no; 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 +160,6 @@ } } -Lextok *runstmnts = ZN; - void trackrun(Lextok *n) { @@ -151,11 +200,11 @@ 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 +227,9 @@ 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 +250,15 @@ 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 +318,13 @@ setxus(Lextok *p, int t) { Lextok *m, *n; - has_xu = 1; + has_xu = 1; + + if (m_loss && t == XS) + { printf("spin: warning, %s:%d, 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 +332,7 @@ } 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 +354,6 @@ } } -Lextok *Mtype = (Lextok *) 0; - void setmtype(Lextok *m) { Lextok *n; @@ -332,7 +387,7 @@ } lineno = oln; if (cnt > 256) - fatal("too many mtype elements (>255)", (char *)0); + fatal("too many mtype elements (>255)", (char *)0); } int @@ -389,11 +444,11 @@ 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 +463,13 @@ 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 +483,9 @@ if (m->rgt) printf("\t"); } } + +if (1) printf("\t{scope %s}", sp->bscp); + printf("\n"); } @@ -440,10 +503,9 @@ 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; --- /sys/src/cmd/spin/tl.h Thu Nov 17 15:33:26 2011 +++ /sys/src/cmd/spin/tl.h Thu Nov 17 15:33:22 2011 @@ -82,7 +82,7 @@ Symbol *getsym(Symbol *); Symbol *DoDump(Node *); -char *emalloc(int); /* in main.c */ +extern char *emalloc(size_t); /* in main.c */ int anywhere(int, Node *, Node *); int dump_cond(Node *, Node *, int); @@ -100,6 +100,10 @@ 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); --- /sys/src/cmd/spin/tl_buchi.c Thu Nov 17 15:33:37 2011 +++ /sys/src/cmd/spin/tl_buchi.c Thu Nov 17 15:33:31 2011 @@ -15,6 +15,7 @@ #include "tl.h" extern int tl_verbose, tl_clutter, Total, Max_Red; +extern char *claim_name; FILE *tl_out; /* if standalone: = stdout; */ @@ -38,6 +39,13 @@ static State *never = (State *) 0; static int hitsall; +void +ini_buchi(void) +{ + never = (State *) 0; + hitsall = 0; +} + static int sametrans(Transition *s, Transition *t) { @@ -626,13 +634,13 @@ 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"); --- /sys/src/cmd/spin/tl_cache.c Thu Nov 17 15:33:47 2011 +++ /sys/src/cmd/spin/tl_cache.c Thu Nov 17 15:33:42 2011 @@ -28,6 +28,14 @@ extern void fatal(char *, char *); int sameform(Node *, Node *); +void +ini_cache(void) +{ + stored = (Cache *) 0; + Caches = 0; + CacheHits = 0; +} + #if 0 void cache_dump(void) --- /sys/src/cmd/spin/tl_lex.c Thu Nov 17 15:33:55 2011 +++ /sys/src/cmd/spin/tl_lex.c Thu Nov 17 15:33:51 2011 @@ -18,6 +18,7 @@ static Symbol *symtab[Nhash+1]; static int tl_lex(void); +extern int tl_peek(int); extern YYSTYPE tl_yylval; extern char yytext[]; @@ -54,12 +55,79 @@ 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)) + { peek_buf[0] = c; + j = 1; + while (j < (int) sizeof(peek_buf) && isalnum((int)(c = tl_peek(i)))) + { 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, "eventually") == 0 + || strcmp(peek_buf, "until") == 0 + || strcmp(peek_buf, "next") == 0) + { return 0; + } + } else + { char c_nxt = tl_peek(i); + if (((c == 'U' || c == 'V' || c == 'X') && !isalnum_(c_prev) && !isalnum_(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 +142,17 @@ } 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); + 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 +161,28 @@ 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("not", yytext) == 0) + { Token(NOT); + } tl_yylval = tl_nn(PREDICATE,ZN,ZN); tl_yylval->sym = tl_lookup(yytext); return PREDICATE; } + if (c == '<') { c = tl_Getchar(); if (c == '>') --- /sys/src/cmd/spin/tl_main.c Thu Nov 17 15:34:05 2011 +++ /sys/src/cmd/spin/tl_main.c Thu Nov 17 15:34:00 2011 @@ -21,7 +21,10 @@ 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 +41,15 @@ return -1; } +int +tl_peek(int n) +{ + if (cnt+n < hasuform) + { return uform[cnt+n]; + } + return -1; +} + void tl_balanced(void) { int i; @@ -79,16 +91,33 @@ int tl_main(int argc, char *argv[]) { int i; - extern int verbose, xspin; - tl_verbose = verbose; + extern int /* verbose, */ xspin; + + tl_verbose = 0; /* was: tl_verbose = verbose; */ 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') @@ -100,6 +129,10 @@ case 'v': tl_verbose++; 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; --- /sys/src/cmd/spin/tl_parse.c Thu Nov 17 15:34:23 2011 +++ /sys/src/cmd/spin/tl_parse.c Thu Nov 17 15:34:17 2011 @@ -48,7 +48,6 @@ break; case ALWAYS: tl_yychar = tl_yylex(); - ptr = tl_factor(); #ifndef NO_OPT if (ptr->ntyp == FALSE @@ -385,7 +384,10 @@ void tl_parse(void) -{ Node *n = tl_formula(); +{ Node *n; + + /* tl_verbose = 1; */ + n = tl_formula(); if (tl_verbose) { printf("formula: "); dump(n); --- /sys/src/cmd/spin/tl_rewrt.c Thu Nov 17 15:34:32 2011 +++ /sys/src/cmd/spin/tl_rewrt.c Thu Nov 17 15:34:27 2011 @@ -18,6 +18,12 @@ static Node *can = ZN; +void +ini_rewrt(void) +{ + can = ZN; +} + Node * right_linked(Node *n) { @@ -146,7 +152,10 @@ 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) --- /sys/src/cmd/spin/tl_trans.c Thu Nov 17 15:34:45 2011 +++ /sys/src/cmd/spin/tl_trans.c Thu Nov 17 15:34:38 2011 @@ -15,7 +15,7 @@ #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; @@ -51,6 +51,24 @@ 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 +119,8 @@ 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; } @@ -342,7 +359,7 @@ 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"); @@ -722,6 +739,8 @@ 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 +778,7 @@ #ifdef NXT case NEXT: + Assert(now->lft != ZN, now->ntyp); nx = dupnode(now->lft); nx->nxt = g->Next; g->Next = nx; --- /sys/src/cmd/spin/vars.c Thu Nov 17 15:34:57 2011 +++ /sys/src/cmd/spin/vars.c Thu Nov 17 15:34:50 2011 @@ -110,6 +110,7 @@ } } lineno = oln; Fname = ofnm; + return 1; } @@ -145,7 +146,7 @@ } 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+u, t); non_fatal("value (%s) truncated in assignment", buf); } return (int)(i+s+u); @@ -159,9 +160,12 @@ 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 +219,12 @@ 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 +236,15 @@ 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); @@ -266,7 +277,7 @@ 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 +314,8 @@ 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"); @@ -341,7 +352,7 @@ 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); } } } } --- /sys/src/cmd/spin/version.h Thu Nov 17 15:35:04 2011 +++ /sys/src/cmd/spin/version.h Thu Nov 17 15:35:00 2011 @@ -1 +1 @@ -#define Version "Spin Version 4.3.0 -- 22 June 2007" +#define SpinVersion "Spin Version 6.1.0 -- 4 May 2011" --- /sys/man/1/spin Thu Nov 17 15:35:13 2011 +++ /sys/man/1/spin Thu Nov 17 15:35:08 2011 @@ -1,105 +1,25 @@ .TH SPIN 1 .SH NAME -spin - verification tool for models of concurrent systems +Spin - verification of multithreaded systems .SH SYNOPSIS .B spin -.B -a -[ -.B -m -] -[ -.BI -P cpp -] -.I file -.PP -.B spin -[ -.B -bglmprsv -] -[ -.BI -n N -] -[ -.BI -P cpp -] -.I file -.PP -.B spin -.B -c -[ -.B -t -] -[ -.BI -P cpp -] -.I file -.PP -.B spin -.B -d -[ -.BI -P cpp -] -.I file -.PP -.B spin -.B -f -.I ltl -.PP -.B spin -.B -F -.I file -.PP -.B spin -.B -i -[ -.B -bglmprsv -] -[ -.BI -n N -] -[ -.BI -P cpp -] -.I file -.PP -.B spin -.B -M -[ -.B -t -] -[ -.BI -P cpp -] -.I file -.PP +.B -V +.br .B spin -.BR -t [ \fIN ] [ -.B -bglmprsv -] -[ -.BI -j N -] -[ -.BI -P cpp +.B options ] .I file -.PP -.B spin -.B -V .SH DESCRIPTION .I Spin is a tool for analyzing the logical consistency of -asynchronous systems, specifically distributed software -amd communication protocols. -A verification model of the system is first specified -in a guarded command language called -.IR Promela . -This specification language, described in the reference, -allows for the modeling of dynamic creation of -asynchronous processes, -nondeterministic case selection, loops, gotos, local and -global variables. +asynchronous systems, specifically distributed software, +multi-threaded systems, and communication protocols. +A model of the system is specified +in a guarded command language called Promela (process meta language). +This modeling language supports dynamic creation of +processes, nondeterministic case selection, loops, gotos, +local and global variables. It also allows for a concise specification of logical correctness requirements, including, but not restricted to requirements expressed in linear temporal logic. @@ -110,23 +30,28 @@ can perform interactive, guided, or random simulations of the system's execution. It can also generate a C program that performs an exhaustive -or approximate verification of the correctness requirements -for the system. +verification of the correctness requirements for the system. +The main options supported are as follows. (You can always get +a full list of current options with the command "spin --"). . .TP .B -a -Generate a verifier (model checker) for the specification. -The output is written into a set of C files, named -.BR pan.[cbhmt] , +Generate a verifier (a model checker) for the specification. +The output is written into a set of C files named +.BR pan.[ cbhmt ] , that can be compiled .RB ( "pcc pan.c" ) to produce an executable verifier. The online .I spin -manuals (see below) contain +manuals contain the details on compilation and use of the verifiers. . .TP +.B -b +Do not execute printf statements in a simulation run. +. +.TP .B -c Produce an ASCII approximation of a message sequence chart for a random or guided (when combined with @@ -135,6 +60,15 @@ .BR -M . . .TP +.B -Dxxx +Pass +.I -Dxxx +to the preprocessor (see also +.I -E +and +.IR -I ). +. +.TP .B -d Produce symbol table information for the model specified in .IR file . @@ -148,6 +82,21 @@ name of the structure declaration that contains the variable. . .TP +.B -Exxx +Pass +.I xxx +to the preprocessor (see also +.I -D +and +.IR -I ). +. +.TP +.B -e +If the specification contains multiple never claims, or ltl properties, +compute the synchronous product of all claims and write the result +to the standard output. +. +.TP .BI -f " ltl" Translate the LTL formula .I ltl @@ -176,6 +125,9 @@ single argument to the .I spin command. +.br +This option has largely been replaced with the support +for inline specification of ltl formula, in Spin version 6.0. . .TP .BI -F " file" @@ -201,6 +153,25 @@ is meant to solve those problems.) . .TP +.B -g +In combination with option +.BR -p , +print all global variable updates in a simulation run. +. +.TP +.B -h +At the end of a simulation run, print the value of the seed +that was used for the random number generator. +By specifying the same seed with the +.B -n +option, the exact +run can be repeated later. +. +.TP +.B -I +Show the result of inlining and preprocessing. +. +.TP .B -i Perform an interactive simulation, prompting the user at every execution step that requires a nondeterministic choice @@ -208,6 +179,30 @@ when execution is deterministic. . .TP +.BI -j N +Skip printing for the first +.I N +steps in a simulation run. +. +.TP +.B -J +Reverse the evaluation order for nested unless statements, +e.g., to match the way in which Java handles exceptions. +. +.TP +.BI -k " file" +Use the file name +.I file +as the trail-file, see also +.BR -t . +. +.TP +.B -l +In combination with option +.BR -p , +include all local variable updates in the output of a simulation run. +. +.TP .B -M Produce a message sequence chart in Postscript form for a random simulation or a guided simulation @@ -237,60 +232,56 @@ .IR N . . .TP -.B -t -Perform a guided simulation, following the error trail that -was produces by an earlier verification run, see the online manuals -for the details on verification. +.BI -N " file" +Use the never claim stored in +.I file +to generate the verified (see +.BR -a ). . .TP -.B -V -Prints the -.I spin -version number and exits. -. -.PP -With only a filename as an argument and no options, -.I spin -performs a random simulation of the model specified in -the file (standard input is the default if the filename is omitted). -If option -.B -i -is added, the simulation is -.IR interactive , -or if option -.B -t -is added, the simulation is -.IR guided . -.PP -The simulation normally does not generate output, except what is generated -explicitly by the user within the model with -.I printf -statements, and some details about the final state that is -reached after the simulation completes. -The group of options -.B -bglmprsv -sets the desired level of information that the user wants -about a random, guided, or interactive simulation run. -Every line of output normally contains a reference to the source -line in the specification that generated it. +.BI -O +Use the original scope rules from pre-Spin version 6. . .TP -.B -b -Suppress the execution of -.I printf -statements within the model. -.TP -.B -g -Show at each time step the current value of global variables. -.TP -.B -l -In combination with option -.BR -p , -show the current value of local variables of the process. +.BI -o [123] +Turn off data-flow optimization ( +.IR -o1 ). +Do not hide write-only variables ( +.I -o2 +) during verification. +Turn off statement merging ( +.I -o3 +) during verification. +Turn on rendezvous optimization ( +.I -o4 +) during verification. +Turn on case caching ( +.I -o5 +) to reduce the size of pan.m, +but losing accuracy in reachability reports. +. +.TP +.BI -O +Use the scope rules pre-version 6.0. In this case there are only two +possible levels of scope for all data declarations: global, or proctype local. +In version 6.0 and later there is a third level of scope: inlines or blocks. +. +.TP +.BI -P xxx +Use the command +.I xxx +for preprocessing instead of the standard C preprocessor. +. .TP .B -p -Show at each simulation step which process changed state, -and what source statement was executed. +Include all statement executions in the output of simulation runs. +. +.TP +.BI -q N +Suppress the output generated for channel +.B N +during simulation runs. +. .TP .B -r Show all message-receive events, giving @@ -298,34 +289,86 @@ and the corresponding the source line number. For each message parameter, show the message type and the message channel number and name. +. .TP .B -s -Show all message-send events. +Include all send operations in the output of simulation runs. +. +.TP +.B -T +Do not automatically indent the printf output of process +.I i +with +.I i +tabs. +. +.TP +.B -t[\f2N\f1] +Perform a guided simulation, following the [\f2N\f1th] error trail that +was produces by an earlier verification run, see the online manuals +for the details on verification. By default the error trail is looked for +in a file with the same basename as the model, and with extension .trail. +See also +.BR -k . +. .TP .B -v Verbose mode, add some more detail, and generate more hints and warnings about the model. +. +.TP +.B -V +Prints the +.I spin +version number and exit. +. +.PP +With only a filename as an argument and no option flags, +.I spin +performs a random simulation of the model specified in +the file. +This normally does not generate output, except what is generated +explicitly by the user within the model with +.I printf +statements, and some details about the final state that is +reached after the simulation completes. +The group of options +.B -bgilmprstv +is used to set the desired level of information that the user wants +about a random, guided, or interactive simulation run. +Every line of output normally contains a reference to the source +line in the specification that generated it. +If option +.B -i +is included, the simulation i +.IR interactive , +or if option +.B -t +or +.BI -k file +is added, the simulation is +.IR guided . +. .SH SOURCE .B /sys/src/cmd/spin .SH SEE ALSO .in +4 .ti -4 -.BR http://spinroot.com : -.BR GettingStarted.pdf , -.BR Roadmap.pdf , -.BR Manual.pdf , -.BR WhatsNew.pdf , -.B Exercises.pdf +.B http://spinroot.com/spin/Man/ .br .in -4 G.J. Holzmann, -.IR "Design and Validation of Computer Protocols" , -Prentice Hall, 1991. +`The Spin Model Checker (Primer and Reference Manual),' +Addison-Wesley, Reading, Mass., 2004. +.br +—, `The model checker Spin,' +.IR "IEEE Trans. on SE" , +Vol, 23, No. 5, May 1997. .br —, `Design and validation of protocols: a tutorial,' .IR "Computer Networks and ISDN Systems" , Vol. 25, No. 9, 1993, pp. 981-1017. .br -—, `The model checker Spin,' -.IR "IEEE Trans. on SE" , -Vol, 23, No. 5, May 1997. +—, +.IR "Design and Validation of Computer Protocols" , +Prentice Hall, Englewood Cliffs, NJ, 1991.