run.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. /***** spin: run.c *****/
  2. /* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */
  3. /* All Rights Reserved. This software is for educational purposes only. */
  4. /* Permission is given to distribute this code provided that this intro- */
  5. /* ductory message is not removed and no monies are exchanged. */
  6. /* No guarantee is expressed or implied by the distribution of this code. */
  7. /* Software written by Gerard J. Holzmann as part of the book: */
  8. /* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */
  9. /* Prentice Hall, Englewood Cliffs, NJ, 07632. */
  10. /* Send bug-reports and/or questions to: gerard@research.bell-labs.com */
  11. #include <stdlib.h>
  12. #include "spin.h"
  13. #ifdef PC
  14. #include "y_tab.h"
  15. #else
  16. #include "y.tab.h"
  17. #endif
  18. extern RunList *X, *run;
  19. extern Symbol *Fname;
  20. extern Element *LastStep;
  21. extern int Rvous, lineno, Tval, interactive, MadeChoice;
  22. extern int TstOnly, verbose, s_trail, xspin, jumpsteps, depth;
  23. extern int nproc, nstop, no_print, like_java;
  24. static long Seed = 1;
  25. 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);
  29. void
  30. Srand(unsigned int s)
  31. { Seed = s;
  32. }
  33. long
  34. Rand(void)
  35. { /* CACM 31(10), Oct 1988 */
  36. Seed = 16807*(Seed%127773) - 2836*(Seed/127773);
  37. if (Seed <= 0) Seed += 2147483647;
  38. return Seed;
  39. }
  40. Element *
  41. rev_escape(SeqList *e)
  42. { Element *r;
  43. if (!e)
  44. return (Element *) 0;
  45. if (r = rev_escape(e->nxt)) /* reversed order */
  46. return r;
  47. return eval_sub(e->this->frst);
  48. }
  49. Element *
  50. eval_sub(Element *e)
  51. { Element *f, *g;
  52. SeqList *z;
  53. int i, j, k;
  54. if (!e->n)
  55. return ZE;
  56. #ifdef DEBUG
  57. printf("\n\teval_sub(%d %s: line %d) ",
  58. e->Seqno, e->esc?"+esc":"", e->n?e->n->ln:0);
  59. comment(stdout, e->n, 0);
  60. printf("\n");
  61. #endif
  62. if (e->n->ntyp == GOTO)
  63. { if (Rvous) return ZE;
  64. LastStep = e; f = get_lab(e->n, 1);
  65. cross_dsteps(e->n, f->n);
  66. return f;
  67. }
  68. if (e->n->ntyp == UNLESS)
  69. { /* escapes were distributed into sequence */
  70. return eval_sub(e->sub->this->frst);
  71. } else if (e->sub) /* true for IF, DO, and UNLESS */
  72. { Element *has_else = ZE;
  73. Element *bas_else = ZE;
  74. int nr_else, nr_choices = 0;
  75. if (interactive
  76. && !MadeChoice && !E_Check
  77. && !Escape_Check
  78. && !(e->status&(D_ATOM))
  79. && depth >= jumpsteps)
  80. { printf("Select stmnt (");
  81. whoruns(0); printf(")\n");
  82. if (nproc-nstop > 1)
  83. printf("\tchoice 0: other process\n");
  84. }
  85. for (z = e->sub, j=0; z; z = z->nxt)
  86. { j++;
  87. if (interactive
  88. && !MadeChoice && !E_Check
  89. && !Escape_Check
  90. && !(e->status&(D_ATOM))
  91. && depth >= jumpsteps
  92. && z->this->frst
  93. && (xspin || (verbose&32) || Enabled0(z->this->frst)))
  94. { if (z->this->frst->n->ntyp == ELSE)
  95. { has_else = (Rvous)?ZE:z->this->frst->nxt;
  96. nr_else = j;
  97. continue;
  98. }
  99. printf("\tchoice %d: ", j);
  100. #if 0
  101. if (z->this->frst->n)
  102. printf("line %d, ", z->this->frst->n->ln);
  103. #endif
  104. if (!Enabled0(z->this->frst))
  105. printf("unexecutable, ");
  106. else
  107. nr_choices++;
  108. comment(stdout, z->this->frst->n, 0);
  109. printf("\n");
  110. } }
  111. if (nr_choices == 0 && has_else)
  112. printf("\tchoice %d: (else)\n", nr_else);
  113. if (interactive && depth >= jumpsteps
  114. && !Escape_Check
  115. && !(e->status&(D_ATOM))
  116. && !E_Check)
  117. { if (!MadeChoice)
  118. { char buf[256];
  119. if (xspin)
  120. printf("Make Selection %d\n\n", j);
  121. else
  122. printf("Select [0-%d]: ", j);
  123. fflush(stdout);
  124. scanf("%s", buf);
  125. if (isdigit(buf[0]))
  126. k = atoi(buf);
  127. else
  128. { if (buf[0] == 'q')
  129. alldone(0);
  130. k = -1;
  131. }
  132. } else
  133. { k = MadeChoice;
  134. MadeChoice = 0;
  135. }
  136. if (k < 1 || k > j)
  137. { if (k != 0) printf("\tchoice outside range\n");
  138. return ZE;
  139. }
  140. k--;
  141. } else
  142. { if (e->n && e->n->indstep >= 0)
  143. k = 0; /* select 1st executable guard */
  144. else
  145. k = Rand()%j; /* nondeterminism */
  146. }
  147. has_else = ZE;
  148. bas_else = ZE;
  149. for (i = 0, z = e->sub; i < j+k; i++)
  150. { if (z->this->frst
  151. && z->this->frst->n->ntyp == ELSE)
  152. { bas_else = z->this->frst;
  153. has_else = (Rvous)?ZE:bas_else->nxt;
  154. if (!interactive || depth < jumpsteps
  155. || Escape_Check
  156. || (e->status&(D_ATOM)))
  157. { z = (z->nxt)?z->nxt:e->sub;
  158. continue;
  159. }
  160. }
  161. if (i >= k)
  162. { if (f = eval_sub(z->this->frst))
  163. return f;
  164. else if (interactive && depth >= jumpsteps
  165. && !(e->status&(D_ATOM)))
  166. { if (!E_Check && !Escape_Check)
  167. printf("\tunexecutable\n");
  168. return ZE;
  169. } }
  170. z = (z->nxt)?z->nxt:e->sub;
  171. }
  172. LastStep = bas_else;
  173. return has_else;
  174. } else
  175. { if (e->n->ntyp == ATOMIC
  176. || e->n->ntyp == D_STEP)
  177. { f = e->n->sl->this->frst;
  178. g = e->n->sl->this->last;
  179. g->nxt = e->nxt;
  180. if (!(g = eval_sub(f))) /* atomic guard */
  181. return ZE;
  182. return g;
  183. } else if (e->n->ntyp == NON_ATOMIC)
  184. { f = e->n->sl->this->frst;
  185. g = e->n->sl->this->last;
  186. g->nxt = e->nxt; /* close it */
  187. return eval_sub(f);
  188. } else if (e->n->ntyp == '.')
  189. { if (!Rvous) return e->nxt;
  190. return eval_sub(e->nxt);
  191. } else
  192. { SeqList *x;
  193. if (!(e->status & (D_ATOM))
  194. && e->esc && verbose&32)
  195. { printf("Stmnt [");
  196. comment(stdout, e->n, 0);
  197. printf("] has escape(s): ");
  198. for (x = e->esc; x; x = x->nxt)
  199. { printf("[");
  200. g = x->this->frst;
  201. if (g->n->ntyp == ATOMIC
  202. || g->n->ntyp == NON_ATOMIC)
  203. g = g->n->sl->this->frst;
  204. comment(stdout, g->n, 0);
  205. printf("] ");
  206. }
  207. printf("\n");
  208. }
  209. if (!(e->status & D_ATOM)) /* escapes don't reach inside d_steps */
  210. { Escape_Check++;
  211. if (like_java)
  212. { if (g = rev_escape(e->esc))
  213. { if (verbose&4)
  214. printf("\tEscape taken\n");
  215. Escape_Check--;
  216. return g;
  217. }
  218. } else
  219. { for (x = e->esc; x; x = x->nxt)
  220. { if (g = eval_sub(x->this->frst))
  221. { if (verbose&4)
  222. printf("\tEscape taken\n");
  223. Escape_Check--;
  224. return g;
  225. } } }
  226. Escape_Check--;
  227. }
  228. switch (e->n->ntyp) {
  229. case TIMEOUT: case RUN:
  230. case PRINT:
  231. case ASGN: case ASSERT:
  232. case 's': case 'r': case 'c':
  233. /* toplevel statements only */
  234. LastStep = e;
  235. default:
  236. break;
  237. }
  238. if (Rvous)
  239. {
  240. return (eval_sync(e))?e->nxt:ZE;
  241. }
  242. return (eval(e->n))?e->nxt:ZE;
  243. }
  244. }
  245. return ZE; /* not reached */
  246. }
  247. static int
  248. eval_sync(Element *e)
  249. { /* allow only synchronous receives
  250. and related node types */
  251. Lextok *now = (e)?e->n:ZN;
  252. if (!now
  253. || now->ntyp != 'r'
  254. || now->val >= 2 /* no rv with a poll */
  255. || !q_is_sync(now))
  256. {
  257. return 0;
  258. }
  259. LastStep = e;
  260. return eval(now);
  261. }
  262. static int
  263. assign(Lextok *now)
  264. { int t;
  265. if (TstOnly) return 1;
  266. switch (now->rgt->ntyp) {
  267. case FULL: case NFULL:
  268. case EMPTY: case NEMPTY:
  269. case RUN: case LEN:
  270. t = BYTE;
  271. break;
  272. default:
  273. t = Sym_typ(now->rgt);
  274. break;
  275. }
  276. typ_ck(Sym_typ(now->lft), t, "assignment");
  277. return setval(now->lft, eval(now->rgt));
  278. }
  279. static int
  280. nonprogress(void) /* np_ */
  281. { RunList *r;
  282. for (r = run; r; r = r->nxt)
  283. { if (has_lab(r->pc, 4)) /* 4=progress */
  284. return 0;
  285. }
  286. return 1;
  287. }
  288. int
  289. eval(Lextok *now)
  290. {
  291. if (now) {
  292. lineno = now->ln;
  293. Fname = now->fn;
  294. #ifdef DEBUG
  295. printf("eval ");
  296. comment(stdout, now, 0);
  297. printf("\n");
  298. #endif
  299. switch (now->ntyp) {
  300. case CONST: return now->val;
  301. case '!': return !eval(now->lft);
  302. case UMIN: return -eval(now->lft);
  303. case '~': return ~eval(now->lft);
  304. case '/': return (eval(now->lft) / eval(now->rgt));
  305. case '*': return (eval(now->lft) * eval(now->rgt));
  306. case '-': return (eval(now->lft) - eval(now->rgt));
  307. case '+': return (eval(now->lft) + eval(now->rgt));
  308. case '%': return (eval(now->lft) % eval(now->rgt));
  309. case LT: return (eval(now->lft) < eval(now->rgt));
  310. case GT: return (eval(now->lft) > eval(now->rgt));
  311. case '&': return (eval(now->lft) & eval(now->rgt));
  312. case '^': return (eval(now->lft) ^ eval(now->rgt));
  313. case '|': return (eval(now->lft) | eval(now->rgt));
  314. case LE: return (eval(now->lft) <= eval(now->rgt));
  315. case GE: return (eval(now->lft) >= eval(now->rgt));
  316. case NE: return (eval(now->lft) != eval(now->rgt));
  317. case EQ: return (eval(now->lft) == eval(now->rgt));
  318. case OR: return (eval(now->lft) || eval(now->rgt));
  319. case AND: return (eval(now->lft) && eval(now->rgt));
  320. case LSHIFT: return (eval(now->lft) << eval(now->rgt));
  321. case RSHIFT: return (eval(now->lft) >> eval(now->rgt));
  322. case '?': return (eval(now->lft) ? eval(now->rgt->lft)
  323. : eval(now->rgt->rgt));
  324. case 'p': return remotevar(now); /* only _p allowed */
  325. case 'q': return remotelab(now);
  326. case 'R': return qrecv(now, 0); /* test only */
  327. case LEN: return qlen(now);
  328. case FULL: return (qfull(now));
  329. case EMPTY: return (qlen(now)==0);
  330. case NFULL: return (!qfull(now));
  331. case NEMPTY: return (qlen(now)>0);
  332. case ENABLED: if (s_trail) return 1;
  333. return pc_enabled(now->lft);
  334. case EVAL: return eval(now->lft);
  335. case PC_VAL: return pc_value(now->lft);
  336. case NONPROGRESS: return nonprogress();
  337. case NAME: return getval(now);
  338. case TIMEOUT: return Tval;
  339. case RUN: return TstOnly?1:enable(now);
  340. case 's': return qsend(now); /* send */
  341. case 'r': return qrecv(now, 1); /* receive or poll */
  342. case 'c': return eval(now->lft); /* condition */
  343. case PRINT: return TstOnly?1:interprint(stdout, now);
  344. case ASGN: return assign(now);
  345. case ASSERT: if (TstOnly || eval(now->lft)) return 1;
  346. non_fatal("assertion violated", (char *) 0);
  347. printf("spin: text of failed assertion: assert(");
  348. comment(stdout, now->lft, 0);
  349. printf(")\n");
  350. if (s_trail && !xspin) return 1;
  351. wrapup(1); /* doesn't return */
  352. case IF: case DO: case BREAK: case UNLESS: /* compound */
  353. case '.': return 1; /* return label for compound */
  354. case '@': return 0; /* stop state */
  355. case ELSE: return 1; /* only hit here in guided trails */
  356. default : printf("spin: bad node type %d (run)\n", now->ntyp);
  357. if (s_trail) printf("spin: trail file doesn't match spec?\n");
  358. fatal("aborting", 0);
  359. }}
  360. return 0;
  361. }
  362. int
  363. interprint(FILE *fd, Lextok *n)
  364. { Lextok *tmp = n->lft;
  365. char c, *s = n->sym->name;
  366. int i, j; char lbuf[16];
  367. extern char Buf[];
  368. char tBuf[1024];
  369. Buf[0] = '\0';
  370. if (!no_print)
  371. if (!s_trail || depth >= jumpsteps) {
  372. for (i = 0; i < (int) strlen(s); i++)
  373. switch (s[i]) {
  374. case '\"': break; /* ignore */
  375. case '\\':
  376. switch(s[++i]) {
  377. case 't': strcat(Buf, "\t"); break;
  378. case 'n': strcat(Buf, "\n"); break;
  379. default: goto onechar;
  380. }
  381. break;
  382. case '%':
  383. if ((c = s[++i]) == '%')
  384. { strcat(Buf, "%"); /* literal */
  385. break;
  386. }
  387. if (!tmp)
  388. { non_fatal("too few print args %s", s);
  389. break;
  390. }
  391. j = eval(tmp->lft);
  392. tmp = tmp->rgt;
  393. switch(c) {
  394. case 'c': sprintf(lbuf, "%c", j); break;
  395. case 'd': sprintf(lbuf, "%d", j); break;
  396. case 'e': strcpy(tBuf, Buf); /* event name */
  397. Buf[0] = '\0';
  398. sr_buf(j, 1);
  399. strcpy(lbuf, Buf);
  400. strcpy(Buf, tBuf);
  401. break;
  402. case 'o': sprintf(lbuf, "%o", j); break;
  403. case 'u': sprintf(lbuf, "%u", (unsigned) j); break;
  404. case 'x': sprintf(lbuf, "%x", j); break;
  405. default: non_fatal("bad print cmd: '%s'", &s[i-1]);
  406. lbuf[0] = '\0'; break;
  407. }
  408. goto append;
  409. default:
  410. onechar: lbuf[0] = s[i]; lbuf[1] = '\0';
  411. append: strcat(Buf, lbuf);
  412. break;
  413. }
  414. dotag(fd, Buf);
  415. }
  416. if (strlen(Buf) > 1024) fatal("printf string too long", 0);
  417. return 1;
  418. }
  419. static int
  420. Enabled1(Lextok *n)
  421. { int i; int v = verbose;
  422. if (n)
  423. switch (n->ntyp) {
  424. case 'c':
  425. if (has_typ(n->lft, RUN))
  426. return 1; /* conservative */
  427. /* else fall through */
  428. default: /* side-effect free */
  429. verbose = 0;
  430. E_Check++;
  431. i = eval(n);
  432. E_Check--;
  433. verbose = v;
  434. return i;
  435. case PRINT: case ASGN: case ASSERT:
  436. return 1;
  437. case 's':
  438. if (q_is_sync(n))
  439. { if (Rvous) return 0;
  440. TstOnly = 1; verbose = 0;
  441. E_Check++;
  442. i = eval(n);
  443. E_Check--;
  444. TstOnly = 0; verbose = v;
  445. return i;
  446. }
  447. return (!qfull(n));
  448. case 'r':
  449. if (q_is_sync(n))
  450. return 0; /* it's never a user-choice */
  451. n->ntyp = 'R'; verbose = 0;
  452. E_Check++;
  453. i = eval(n);
  454. E_Check--;
  455. n->ntyp = 'r'; verbose = v;
  456. return i;
  457. }
  458. return 0;
  459. }
  460. int
  461. Enabled0(Element *e)
  462. { SeqList *z;
  463. if (!e || !e->n)
  464. return 0;
  465. switch (e->n->ntyp) {
  466. case '@':
  467. return X->pid == (nproc-nstop-1);
  468. case '.':
  469. return 1;
  470. case GOTO:
  471. if (Rvous) return 0;
  472. return 1;
  473. case UNLESS:
  474. return Enabled0(e->sub->this->frst);
  475. case ATOMIC:
  476. case D_STEP:
  477. case NON_ATOMIC:
  478. return Enabled0(e->n->sl->this->frst);
  479. }
  480. if (e->sub) /* true for IF, DO, and UNLESS */
  481. { for (z = e->sub; z; z = z->nxt)
  482. if (Enabled0(z->this->frst))
  483. return 1;
  484. return 0;
  485. }
  486. for (z = e->esc; z; z = z->nxt)
  487. { if (Enabled0(z->this->frst))
  488. return 1;
  489. }
  490. #if 0
  491. printf("enabled1 ");
  492. comment(stdout, e->n, 0);
  493. printf(" ==> %s\n", Enabled1(e->n)?"yes":"nope");
  494. #endif
  495. return Enabled1(e->n);
  496. }
  497. int
  498. pc_enabled(Lextok *n)
  499. { int i = nproc - nstop;
  500. int pid = eval(n);
  501. int result = 0;
  502. RunList *Y, *oX;
  503. for (Y = run; Y; Y = Y->nxt)
  504. if (--i == pid)
  505. { oX = X; X = Y;
  506. result = Enabled0(Y->pc);
  507. X = oX;
  508. break;
  509. }
  510. return result;
  511. }