1 /***** spin: run.c *****/
3 /* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */
4 /* All Rights Reserved. This software is for educational purposes only. */
5 /* No guarantee whatsoever is expressed or implied by the distribution of */
6 /* this code. Permission is given to distribute this code provided that */
7 /* this introductory message is not removed and no monies are exchanged. */
8 /* Software written by Gerard J. Holzmann. For tool documentation see: */
9 /* http://spinroot.com/ */
10 /* Send all bug-reports and/or questions to: bugs@spinroot.com */
16 extern RunList *X, *run;
18 extern Element *LastStep;
19 extern int Rvous, lineno, Tval, interactive, MadeChoice;
20 extern int TstOnly, verbose, s_trail, xspin, jumpsteps, depth;
21 extern int nproc, nstop, no_print, like_java;
24 static int E_Check = 0, Escape_Check = 0;
26 static int eval_sync(Element *);
27 static int pc_enabled(Lextok *n);
28 extern void sr_buf(int, int);
37 { /* CACM 31(10), Oct 1988 */
38 Seed = 16807*(Seed%127773) - 2836*(Seed/127773);
39 if (Seed <= 0) Seed += 2147483647;
44 rev_escape(SeqList *e)
50 if ((r = rev_escape(e->nxt)) != ZE) /* reversed order */
53 return eval_sub(e->this->frst);
65 printf("\n\teval_sub(%d %s: line %d) ",
66 e->Seqno, e->esc?"+esc":"", e->n?e->n->ln:0);
67 comment(stdout, e->n, 0);
70 if (e->n->ntyp == GOTO)
71 { if (Rvous) return ZE;
72 LastStep = e; f = get_lab(e->n, 1);
73 cross_dsteps(e->n, f->n);
76 if (e->n->ntyp == UNLESS)
77 { /* escapes were distributed into sequence */
78 return eval_sub(e->sub->this->frst);
79 } else if (e->sub) /* true for IF, DO, and UNLESS */
80 { Element *has_else = ZE;
81 Element *bas_else = ZE;
82 int nr_else = 0, nr_choices = 0;
85 && !MadeChoice && !E_Check
87 && !(e->status&(D_ATOM))
88 && depth >= jumpsteps)
89 { printf("Select stmnt (");
90 whoruns(0); printf(")\n");
92 printf("\tchoice 0: other process\n");
94 for (z = e->sub, j=0; z; z = z->nxt)
97 && !MadeChoice && !E_Check
99 && !(e->status&(D_ATOM))
100 && depth >= jumpsteps
102 && (xspin || (verbose&32) || Enabled0(z->this->frst)))
103 { if (z->this->frst->n->ntyp == ELSE)
104 { has_else = (Rvous)?ZE:z->this->frst->nxt;
108 printf("\tchoice %d: ", j);
110 if (z->this->frst->n)
111 printf("line %d, ", z->this->frst->n->ln);
113 if (!Enabled0(z->this->frst))
114 printf("unexecutable, ");
117 comment(stdout, z->this->frst->n, 0);
121 if (nr_choices == 0 && has_else)
122 printf("\tchoice %d: (else)\n", nr_else);
124 if (interactive && depth >= jumpsteps
126 && !(e->status&(D_ATOM))
131 printf("Make Selection %d\n\n", j);
133 printf("Select [0-%d]: ", j);
148 { if (k != 0) printf("\tchoice outside range\n");
153 { if (e->n && e->n->indstep >= 0)
154 k = 0; /* select 1st executable guard */
156 k = Rand()%j; /* nondeterminism */
160 for (i = 0, z = e->sub; i < j+k; i++)
162 && z->this->frst->n->ntyp == ELSE)
163 { bas_else = z->this->frst;
164 has_else = (Rvous)?ZE:bas_else->nxt;
165 if (!interactive || depth < jumpsteps
167 || (e->status&(D_ATOM)))
168 { z = (z->nxt)?z->nxt:e->sub;
173 && ((z->this->frst->n->ntyp == ATOMIC
174 || z->this->frst->n->ntyp == D_STEP)
175 && z->this->frst->n->sl->this->frst->n->ntyp == ELSE))
176 { bas_else = z->this->frst->n->sl->this->frst;
177 has_else = (Rvous)?ZE:bas_else->nxt;
178 if (!interactive || depth < jumpsteps
180 || (e->status&(D_ATOM)))
181 { z = (z->nxt)?z->nxt:e->sub;
186 { if ((f = eval_sub(z->this->frst)) != ZE)
188 else if (interactive && depth >= jumpsteps
189 && !(e->status&(D_ATOM)))
190 { if (!E_Check && !Escape_Check)
191 printf("\tunexecutable\n");
194 z = (z->nxt)?z->nxt:e->sub;
199 { if (e->n->ntyp == ATOMIC
200 || e->n->ntyp == D_STEP)
201 { f = e->n->sl->this->frst;
202 g = e->n->sl->this->last;
204 if (!(g = eval_sub(f))) /* atomic guard */
207 } else if (e->n->ntyp == NON_ATOMIC)
208 { f = e->n->sl->this->frst;
209 g = e->n->sl->this->last;
210 g->nxt = e->nxt; /* close it */
212 } else if (e->n->ntyp == '.')
213 { if (!Rvous) return e->nxt;
214 return eval_sub(e->nxt);
217 if (!(e->status & (D_ATOM))
218 && e->esc && verbose&32)
220 comment(stdout, e->n, 0);
221 printf("] has escape(s): ");
222 for (x = e->esc; x; x = x->nxt)
225 if (g->n->ntyp == ATOMIC
226 || g->n->ntyp == NON_ATOMIC)
227 g = g->n->sl->this->frst;
228 comment(stdout, g->n, 0);
234 if (!(e->status & D_ATOM)) /* escapes don't reach inside d_steps */
235 /* 4.2.4: only the guard of a d_step can have an escape */
239 { if ((g = rev_escape(e->esc)) != ZE)
241 printf("\tEscape taken\n");
246 { for (x = e->esc; x; x = x->nxt)
247 { if ((g = eval_sub(x->this->frst)) != ZE)
249 printf("\tEscape taken\n");
256 switch (e->n->ntyp) {
257 case TIMEOUT: case RUN:
258 case PRINT: case PRINTM:
259 case C_CODE: case C_EXPR:
260 case ASGN: case ASSERT:
261 case 's': case 'r': case 'c':
262 /* toplevel statements only */
269 return (eval_sync(e))?e->nxt:ZE;
271 return (eval(e->n))?e->nxt:ZE;
274 return ZE; /* not reached */
278 eval_sync(Element *e)
279 { /* allow only synchronous receives
280 and related node types */
281 Lextok *now = (e)?e->n:ZN;
285 || now->val >= 2 /* no rv with a poll */
299 if (TstOnly) return 1;
301 switch (now->rgt->ntyp) {
302 case FULL: case NFULL:
303 case EMPTY: case NEMPTY:
308 t = Sym_typ(now->rgt);
311 typ_ck(Sym_typ(now->lft), t, "assignment");
312 return setval(now->lft, eval(now->rgt));
316 nonprogress(void) /* np_ */
319 for (r = run; r; r = r->nxt)
320 { if (has_lab(r->pc, 4)) /* 4=progress */
334 comment(stdout, now, 0);
338 case CONST: return now->val;
339 case '!': return !eval(now->lft);
340 case UMIN: return -eval(now->lft);
341 case '~': return ~eval(now->lft);
343 case '/': return (eval(now->lft) / eval(now->rgt));
344 case '*': return (eval(now->lft) * eval(now->rgt));
345 case '-': return (eval(now->lft) - eval(now->rgt));
346 case '+': return (eval(now->lft) + eval(now->rgt));
347 case '%': return (eval(now->lft) % eval(now->rgt));
348 case LT: return (eval(now->lft) < eval(now->rgt));
349 case GT: return (eval(now->lft) > eval(now->rgt));
350 case '&': return (eval(now->lft) & eval(now->rgt));
351 case '^': return (eval(now->lft) ^ eval(now->rgt));
352 case '|': return (eval(now->lft) | eval(now->rgt));
353 case LE: return (eval(now->lft) <= eval(now->rgt));
354 case GE: return (eval(now->lft) >= eval(now->rgt));
355 case NE: return (eval(now->lft) != eval(now->rgt));
356 case EQ: return (eval(now->lft) == eval(now->rgt));
357 case OR: return (eval(now->lft) || eval(now->rgt));
358 case AND: return (eval(now->lft) && eval(now->rgt));
359 case LSHIFT: return (eval(now->lft) << eval(now->rgt));
360 case RSHIFT: return (eval(now->lft) >> eval(now->rgt));
361 case '?': return (eval(now->lft) ? eval(now->rgt->lft)
362 : eval(now->rgt->rgt));
364 case 'p': return remotevar(now); /* _p for remote reference */
365 case 'q': return remotelab(now);
366 case 'R': return qrecv(now, 0); /* test only */
367 case LEN: return qlen(now);
368 case FULL: return (qfull(now));
369 case EMPTY: return (qlen(now)==0);
370 case NFULL: return (!qfull(now));
371 case NEMPTY: return (qlen(now)>0);
372 case ENABLED: if (s_trail) return 1;
373 return pc_enabled(now->lft);
374 case EVAL: return eval(now->lft);
375 case PC_VAL: return pc_value(now->lft);
376 case NONPROGRESS: return nonprogress();
377 case NAME: return getval(now);
379 case TIMEOUT: return Tval;
380 case RUN: return TstOnly?1:enable(now);
382 case 's': return qsend(now); /* send */
383 case 'r': return qrecv(now, 1); /* receive or poll */
384 case 'c': return eval(now->lft); /* condition */
385 case PRINT: return TstOnly?1:interprint(stdout, now);
386 case PRINTM: return TstOnly?1:printm(stdout, now);
387 case ASGN: return assign(now);
389 case C_CODE: printf("%s:\t", now->sym->name);
390 plunk_inline(stdout, now->sym->name, 0);
391 return 1; /* uninterpreted */
393 case C_EXPR: printf("%s:\t", now->sym->name);
394 plunk_expr(stdout, now->sym->name);
396 return 1; /* uninterpreted */
398 case ASSERT: if (TstOnly || eval(now->lft)) return 1;
399 non_fatal("assertion violated", (char *) 0);
400 printf("spin: text of failed assertion: assert(");
401 comment(stdout, now->lft, 0);
403 if (s_trail && !xspin) return 1;
404 wrapup(1); /* doesn't return */
406 case IF: case DO: case BREAK: case UNLESS: /* compound */
407 case '.': return 1; /* return label for compound */
408 case '@': return 0; /* stop state */
409 case ELSE: return 1; /* only hit here in guided trails */
410 default : printf("spin: bad node type %d (run)\n", now->ntyp);
411 if (s_trail) printf("spin: trail file doesn't match spec?\n");
412 fatal("aborting", 0);
418 printm(FILE *fd, Lextok *n)
424 if (!s_trail || depth >= jumpsteps) {
437 interprint(FILE *fd, Lextok *n)
438 { Lextok *tmp = n->lft;
439 char c, *s = n->sym->name;
440 int i, j; char lbuf[512];
446 if (!s_trail || depth >= jumpsteps) {
447 for (i = 0; i < (int) strlen(s); i++)
449 case '\"': break; /* ignore */
452 case 't': strcat(Buf, "\t"); break;
453 case 'n': strcat(Buf, "\n"); break;
454 default: goto onechar;
458 if ((c = s[++i]) == '%')
459 { strcat(Buf, "%"); /* literal */
463 { non_fatal("too few print args %s", s);
469 case 'c': sprintf(lbuf, "%c", j); break;
470 case 'd': sprintf(lbuf, "%d", j); break;
472 case 'e': strcpy(tBuf, Buf); /* event name */
479 case 'o': sprintf(lbuf, "%o", j); break;
480 case 'u': sprintf(lbuf, "%u", (unsigned) j); break;
481 case 'x': sprintf(lbuf, "%x", j); break;
482 default: non_fatal("bad print cmd: '%s'", &s[i-1]);
483 lbuf[0] = '\0'; break;
487 onechar: lbuf[0] = s[i]; lbuf[1] = '\0';
488 append: strcat(Buf, lbuf);
493 if (strlen(Buf) > 4096) fatal("printf string too long", 0);
499 { int i; int v = verbose;
504 if (has_typ(n->lft, RUN))
505 return 1; /* conservative */
506 /* else fall through */
507 default: /* side-effect free */
515 case C_CODE: case C_EXPR:
516 case PRINT: case PRINTM:
517 case ASGN: case ASSERT:
522 { if (Rvous) return 0;
523 TstOnly = 1; verbose = 0;
527 TstOnly = 0; verbose = v;
533 return 0; /* it's never a user-choice */
534 n->ntyp = 'R'; verbose = 0;
538 n->ntyp = 'r'; verbose = v;
551 switch (e->n->ntyp) {
553 return X->pid == (nproc-nstop-1);
560 return Enabled0(e->sub->this->frst);
564 return Enabled0(e->n->sl->this->frst);
566 if (e->sub) /* true for IF, DO, and UNLESS */
567 { for (z = e->sub; z; z = z->nxt)
568 if (Enabled0(z->this->frst))
572 for (z = e->esc; z; z = z->nxt)
573 { if (Enabled0(z->this->frst))
578 comment(stdout, e->n, 0);
579 printf(" ==> %s\n", Enabled1(e->n)?"yes":"nope");
581 return Enabled1(e->n);
585 pc_enabled(Lextok *n)
586 { int i = nproc - nstop;
592 fatal("used: enabled(pid=thisproc) [%s]", X->n->name);
594 for (Y = run; Y; Y = Y->nxt)
597 result = Enabled0(Y->pc);