28e9566dc5
from Ori_B: There were a small number of changes needed from the tarball on spinroot.org: - The mkfile needed to be updated - Memory.h needed to not be included - It needed to invoke /bin/cpp instead of gcc -E - It depended on `yychar`, which our yacc doesn't provide. I'm still figuring out how to use spin, but it seems to do the right thing when testing a few of the examples: % cd $home/src/Spin/Examples/ % spin -a peterson.pml % pcc pan.c -D_POSIX_SOURCE % ./6.out (Spin Version 6.4.7 -- 19 August 2017) + Partial Order Reduction Full statespace search for: never claim - (none specified) assertion violations + acceptance cycles - (not selected) invalid end states + State-vector 32 byte, depth reached 24, errors: 0 40 states, stored 27 states, matched 67 transitions (= stored+matched) 0 atomic steps hash conflicts: 0 (resolved) Stats on memory usage (in Megabytes): 0.002 equivalent memory usage for states (stored*(State-vector + overhead)) 0.292 actual memory usage for states 128.000 memory used for hash table (-w24) 0.534 memory used for DFS stack (-m10000) 128.730 total actual memory usage unreached in proctype user /tmp/Spin/Examples/peterson.pml:20, state 10, "-end-" (1 of 10 states) pan: elapsed time 1.25 seconds pan: rate 32 states/second
359 lines
7.9 KiB
C
359 lines
7.9 KiB
C
/***** spin: pangen4.c *****/
|
|
|
|
/*
|
|
* This file is part of the public release of Spin. It is subject to the
|
|
* terms in the LICENSE file that is included in this source directory.
|
|
* Tool documentation is available at http://spinroot.com
|
|
*/
|
|
|
|
#include "spin.h"
|
|
#include "y.tab.h"
|
|
|
|
extern FILE *tc, *tb;
|
|
extern Queue *qtab;
|
|
extern Symbol *Fname;
|
|
extern int lineno, m_loss, Pid, eventmapnr, multi_oval;
|
|
extern short nocast, has_provided, has_sorted;
|
|
extern const char *R13[], *R14[], *R15[];
|
|
|
|
static void check_proc(Lextok *, int);
|
|
|
|
void
|
|
undostmnt(Lextok *now, int m)
|
|
{ Lextok *v;
|
|
int i, j;
|
|
|
|
if (!now)
|
|
{ fprintf(tb, "0");
|
|
return;
|
|
}
|
|
lineno = now->ln;
|
|
Fname = now->fn;
|
|
switch (now->ntyp) {
|
|
case CONST: case '!': case UMIN:
|
|
case '~': case '/': case '*':
|
|
case '-': case '+': case '%':
|
|
case LT: case GT: case '&':
|
|
case '|': case LE: case GE:
|
|
case NE: case EQ: case OR:
|
|
case AND: case LSHIFT: case RSHIFT:
|
|
case TIMEOUT: case LEN: case NAME:
|
|
case FULL: case EMPTY: case 'R':
|
|
case NFULL: case NEMPTY: case ENABLED:
|
|
case '?': case PC_VAL: case '^':
|
|
case C_EXPR: case GET_P:
|
|
case NONPROGRESS:
|
|
putstmnt(tb, now, m);
|
|
break;
|
|
|
|
case RUN:
|
|
fprintf(tb, "delproc(0, now._nr_pr-1)");
|
|
break;
|
|
|
|
case 's':
|
|
if (Pid == eventmapnr) break;
|
|
|
|
if (m_loss)
|
|
fprintf(tb, "if (_m == 2) ");
|
|
putname(tb, "_m = unsend(", now->lft, m, ")");
|
|
break;
|
|
|
|
case 'r':
|
|
if (Pid == eventmapnr) break;
|
|
|
|
for (v = now->rgt, i=j=0; v; v = v->rgt, i++)
|
|
if (v->lft->ntyp != CONST
|
|
&& v->lft->ntyp != EVAL)
|
|
j++;
|
|
if (j == 0 && now->val >= 2)
|
|
break; /* poll without side-effect */
|
|
|
|
{ int ii = 0, jj;
|
|
|
|
for (v = now->rgt; v; v = v->rgt)
|
|
if ((v->lft->ntyp != CONST
|
|
&& v->lft->ntyp != EVAL))
|
|
ii++; /* nr of things bupped */
|
|
if (now->val == 1)
|
|
{ ii++;
|
|
jj = multi_oval - ii - 1;
|
|
fprintf(tb, "XX = trpt->bup.oval");
|
|
if (multi_oval > 0)
|
|
{ fprintf(tb, "s[%d]", jj);
|
|
jj++;
|
|
}
|
|
fprintf(tb, ";\n\t\t");
|
|
} else
|
|
{ fprintf(tb, "XX = 1;\n\t\t");
|
|
jj = multi_oval - ii - 1;
|
|
}
|
|
|
|
if (now->val < 2) /* not for channel poll */
|
|
for (v = now->rgt, i = 0; v; v = v->rgt, i++)
|
|
{ switch(v->lft->ntyp) {
|
|
case CONST:
|
|
case EVAL:
|
|
fprintf(tb, "unrecv");
|
|
putname(tb, "(", now->lft, m, ", XX-1, ");
|
|
fprintf(tb, "%d, ", i);
|
|
if (v->lft->ntyp == EVAL)
|
|
undostmnt(v->lft->lft, m);
|
|
else
|
|
undostmnt(v->lft, m);
|
|
fprintf(tb, ", %d);\n\t\t", (i==0)?1:0);
|
|
break;
|
|
default:
|
|
fprintf(tb, "unrecv");
|
|
putname(tb, "(", now->lft, m, ", XX-1, ");
|
|
fprintf(tb, "%d, ", i);
|
|
if (v->lft->sym
|
|
&& !strcmp(v->lft->sym->name, "_"))
|
|
{ fprintf(tb, "trpt->bup.oval");
|
|
if (multi_oval > 0)
|
|
fprintf(tb, "s[%d]", jj);
|
|
} else
|
|
putstmnt(tb, v->lft, m);
|
|
|
|
fprintf(tb, ", %d);\n\t\t", (i==0)?1:0);
|
|
if (multi_oval > 0)
|
|
jj++;
|
|
break;
|
|
} }
|
|
jj = multi_oval - ii - 1;
|
|
|
|
if (now->val == 1 && multi_oval > 0)
|
|
jj++; /* new 3.4.0 */
|
|
|
|
for (v = now->rgt, i = 0; v; v = v->rgt, i++)
|
|
{ switch(v->lft->ntyp) {
|
|
case CONST:
|
|
case EVAL:
|
|
break;
|
|
default:
|
|
if (!v->lft->sym
|
|
|| strcmp(v->lft->sym->name, "_") != 0)
|
|
{ nocast=1; putstmnt(tb,v->lft,m);
|
|
nocast=0; fprintf(tb, " = trpt->bup.oval");
|
|
if (multi_oval > 0)
|
|
fprintf(tb, "s[%d]", jj);
|
|
fprintf(tb, ";\n\t\t");
|
|
}
|
|
if (multi_oval > 0)
|
|
jj++;
|
|
break;
|
|
} }
|
|
multi_oval -= ii;
|
|
}
|
|
break;
|
|
|
|
case '@':
|
|
fprintf(tb, "p_restor(II);\n\t\t");
|
|
break;
|
|
|
|
case SET_P:
|
|
fprintf(tb, "((P0 *)pptr((trpt->o_priority >> 8)))");
|
|
fprintf(tb, "->_priority = trpt->o_priority & 255");
|
|
break;
|
|
|
|
case ASGN:
|
|
if (check_track(now) == STRUCT) { break; }
|
|
|
|
nocast=1; putstmnt(tb,now->lft,m);
|
|
nocast=0; fprintf(tb, " = trpt->bup.oval");
|
|
if (multi_oval > 0)
|
|
{ multi_oval--;
|
|
fprintf(tb, "s[%d]", multi_oval-1);
|
|
}
|
|
check_proc(now->rgt, m);
|
|
break;
|
|
|
|
case 'c':
|
|
check_proc(now->lft, m);
|
|
break;
|
|
|
|
case '.':
|
|
case GOTO:
|
|
case ELSE:
|
|
case BREAK:
|
|
break;
|
|
|
|
case C_CODE:
|
|
fprintf(tb, "sv_restor();\n");
|
|
break;
|
|
|
|
case ASSERT:
|
|
case PRINT:
|
|
check_proc(now, m);
|
|
break;
|
|
case PRINTM:
|
|
break;
|
|
|
|
default:
|
|
printf("spin: bad node type %d (.b)\n", now->ntyp);
|
|
alldone(1);
|
|
}
|
|
}
|
|
|
|
int
|
|
any_undo(Lextok *now)
|
|
{ /* is there anything to undo on a return move? */
|
|
if (!now) return 1;
|
|
switch (now->ntyp) {
|
|
case 'c': return any_oper(now->lft, RUN);
|
|
case ASSERT:
|
|
case PRINT: return any_oper(now, RUN);
|
|
|
|
case PRINTM:
|
|
case '.':
|
|
case GOTO:
|
|
case ELSE:
|
|
case BREAK: return 0;
|
|
default: return 1;
|
|
}
|
|
}
|
|
|
|
int
|
|
any_oper(Lextok *now, int oper)
|
|
{ /* check if an expression contains oper operator */
|
|
if (!now) return 0;
|
|
if (now->ntyp == oper)
|
|
return 1;
|
|
return (any_oper(now->lft, oper) || any_oper(now->rgt, oper));
|
|
}
|
|
|
|
static void
|
|
check_proc(Lextok *now, int m)
|
|
{
|
|
if (!now)
|
|
return;
|
|
if (now->ntyp == '@' || now->ntyp == RUN)
|
|
{ fprintf(tb, ";\n\t\t");
|
|
undostmnt(now, m);
|
|
}
|
|
check_proc(now->lft, m);
|
|
check_proc(now->rgt, m);
|
|
}
|
|
|
|
void
|
|
genunio(void)
|
|
{ char buf1[256];
|
|
Queue *q; int i;
|
|
|
|
ntimes(tc, 0, 1, R13);
|
|
for (q = qtab; q; q = q->nxt)
|
|
{ fprintf(tc, "\tcase %d:\n", q->qid);
|
|
|
|
if (has_sorted)
|
|
{ sprintf(buf1, "((Q%d *)z)->contents", q->qid);
|
|
fprintf(tc, "#ifdef HAS_SORTED\n");
|
|
fprintf(tc, "\t\tj = trpt->ipt;\n"); /* ipt was bup.oval */
|
|
fprintf(tc, "#endif\n");
|
|
fprintf(tc, "\t\tfor (k = j; k < ((Q%d *)z)->Qlen; k++)\n",
|
|
q->qid);
|
|
fprintf(tc, "\t\t{\n");
|
|
for (i = 0; i < q->nflds; i++)
|
|
fprintf(tc, "\t\t\t%s[k].fld%d = %s[k+1].fld%d;\n",
|
|
buf1, i, buf1, i);
|
|
fprintf(tc, "\t\t}\n");
|
|
fprintf(tc, "\t\tj = ((Q0 *)z)->Qlen;\n");
|
|
}
|
|
|
|
sprintf(buf1, "((Q%d *)z)->contents[j].fld", q->qid);
|
|
for (i = 0; i < q->nflds; i++)
|
|
fprintf(tc, "\t\t%s%d = 0;\n", buf1, i);
|
|
if (q->nslots==0)
|
|
{ /* check if rendezvous succeeded, 1 level down */
|
|
fprintf(tc, "\t\t_m = (trpt+1)->o_m;\n");
|
|
fprintf(tc, "\t\tif (_m) (trpt-1)->o_pm |= 1;\n");
|
|
fprintf(tc, "\t\tUnBlock;\n");
|
|
} else
|
|
fprintf(tc, "\t\t_m = trpt->o_m;\n");
|
|
|
|
fprintf(tc, "\t\tbreak;\n");
|
|
}
|
|
ntimes(tc, 0, 1, R14);
|
|
for (q = qtab; q; q = q->nxt)
|
|
{ sprintf(buf1, "((Q%d *)z)->contents", q->qid);
|
|
fprintf(tc, " case %d:\n", q->qid);
|
|
if (q->nslots == 0)
|
|
fprintf(tc, "\t\tif (strt) boq = from+1;\n");
|
|
else if (q->nslots > 1) /* shift */
|
|
{ fprintf(tc, "\t\tif (strt && slot<%d)\n",
|
|
q->nslots-1);
|
|
fprintf(tc, "\t\t{\tfor (j--; j>=slot; j--)\n");
|
|
fprintf(tc, "\t\t\t{");
|
|
for (i = 0; i < q->nflds; i++)
|
|
{ fprintf(tc, "\t%s[j+1].fld%d =\n\t\t\t",
|
|
buf1, i);
|
|
fprintf(tc, "\t%s[j].fld%d;\n\t\t\t",
|
|
buf1, i);
|
|
}
|
|
fprintf(tc, "}\n\t\t}\n");
|
|
}
|
|
strcat(buf1, "[slot].fld");
|
|
fprintf(tc, "\t\tif (strt) {\n");
|
|
for (i = 0; i < q->nflds; i++)
|
|
fprintf(tc, "\t\t\t%s%d = 0;\n", buf1, i);
|
|
fprintf(tc, "\t\t}\n");
|
|
if (q->nflds == 1) /* set */
|
|
fprintf(tc, "\t\tif (fld == 0) %s0 = fldvar;\n",
|
|
buf1);
|
|
else
|
|
{ fprintf(tc, "\t\tswitch (fld) {\n");
|
|
for (i = 0; i < q->nflds; i++)
|
|
{ fprintf(tc, "\t\tcase %d:\t%s", i, buf1);
|
|
fprintf(tc, "%d = fldvar; break;\n", i);
|
|
}
|
|
fprintf(tc, "\t\t}\n");
|
|
}
|
|
fprintf(tc, "\t\tbreak;\n");
|
|
}
|
|
ntimes(tc, 0, 1, R15);
|
|
}
|
|
|
|
extern void explain(int);
|
|
|
|
int
|
|
proper_enabler(Lextok *n)
|
|
{
|
|
if (!n) return 1;
|
|
switch (n->ntyp) {
|
|
case NEMPTY: case FULL:
|
|
case NFULL: case EMPTY:
|
|
case LEN: case 'R':
|
|
case NAME:
|
|
has_provided = 1;
|
|
if (strcmp(n->sym->name, "_pid") == 0
|
|
|| strcmp(n->sym->name, "_priority") == 0)
|
|
return 1;
|
|
return (!(n->sym->context));
|
|
|
|
case C_EXPR:
|
|
case CONST:
|
|
case TIMEOUT:
|
|
has_provided = 1;
|
|
return 1;
|
|
|
|
case ENABLED: case PC_VAL:
|
|
case GET_P: /* not SET_P */
|
|
return proper_enabler(n->lft);
|
|
|
|
case '!': case UMIN: case '~':
|
|
return proper_enabler(n->lft);
|
|
|
|
case '/': case '*': case '-': case '+':
|
|
case '%': case LT: case GT: case '&': case '^':
|
|
case '|': case LE: case GE: case NE: case '?':
|
|
case EQ: case OR: case AND: case LSHIFT:
|
|
case RSHIFT: case 'c': /* case ',': */
|
|
return proper_enabler(n->lft) && proper_enabler(n->rgt);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
printf("spin: saw ");
|
|
explain(n->ntyp);
|
|
printf("\n");
|
|
return 0;
|
|
}
|