run.c 14 KB

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