run.c 15 KB

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