run.c 14 KB

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