run.c 15 KB

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