mesg.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. /***** spin: mesg.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 "spin.h"
  12. #ifdef PC
  13. #include "y_tab.h"
  14. #else
  15. #include "y.tab.h"
  16. #endif
  17. #define MAXQ 2500 /* default max # queues */
  18. extern RunList *X;
  19. extern Symbol *Fname;
  20. extern Lextok *Mtype;
  21. extern int verbose, TstOnly, s_trail, analyze, columns;
  22. extern int lineno, depth, xspin, m_loss, jumpsteps;
  23. extern int nproc, nstop;
  24. extern short Have_claim;
  25. Queue *qtab = (Queue *) 0; /* linked list of queues */
  26. Queue *ltab[MAXQ]; /* linear list of queues */
  27. int nqs = 0, firstrow = 1;
  28. char Buf[4096];
  29. static Lextok *n_rem = (Lextok *) 0;
  30. static Queue *q_rem = (Queue *) 0;
  31. static int a_rcv(Queue *, Lextok *, int);
  32. static int a_snd(Queue *, Lextok *);
  33. static int sa_snd(Queue *, Lextok *);
  34. static int s_snd(Queue *, Lextok *);
  35. extern void sr_buf(int, int);
  36. extern void sr_mesg(FILE *, int, int);
  37. extern void putarrow(int, int);
  38. static void sr_talk(Lextok *, int, char *, char *, int, Queue *);
  39. int
  40. cnt_mpars(Lextok *n)
  41. { Lextok *m;
  42. int i=0;
  43. for (m = n; m; m = m->rgt)
  44. i += Cnt_flds(m);
  45. return i;
  46. }
  47. int
  48. qmake(Symbol *s)
  49. { Lextok *m;
  50. Queue *q;
  51. int i; extern int analyze;
  52. if (!s->ini)
  53. return 0;
  54. if (nqs >= MAXQ)
  55. { lineno = s->ini->ln;
  56. Fname = s->ini->fn;
  57. fatal("too many queues (%s)", s->name);
  58. }
  59. if (analyze && nqs >= 255)
  60. { fatal("too many channel types", (char *)0);
  61. }
  62. if (s->ini->ntyp != CHAN)
  63. return eval(s->ini);
  64. q = (Queue *) emalloc(sizeof(Queue));
  65. q->qid = ++nqs;
  66. q->nslots = s->ini->val;
  67. q->nflds = cnt_mpars(s->ini->rgt);
  68. q->setat = depth;
  69. i = max(1, q->nslots); /* 0-slot qs get 1 slot minimum */
  70. q->contents = (int *) emalloc(q->nflds*i*sizeof(int));
  71. q->fld_width = (int *) emalloc(q->nflds*sizeof(int));
  72. q->stepnr = (int *) emalloc(i*sizeof(int));
  73. for (m = s->ini->rgt, i = 0; m; m = m->rgt)
  74. { if (m->sym && m->ntyp == STRUCT)
  75. i = Width_set(q->fld_width, i, getuname(m->sym));
  76. else
  77. q->fld_width[i++] = m->ntyp;
  78. }
  79. q->nxt = qtab;
  80. qtab = q;
  81. ltab[q->qid-1] = q;
  82. return q->qid;
  83. }
  84. int
  85. qfull(Lextok *n)
  86. { int whichq = eval(n->lft)-1;
  87. if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
  88. return (ltab[whichq]->qlen >= ltab[whichq]->nslots);
  89. return 0;
  90. }
  91. int
  92. qlen(Lextok *n)
  93. { int whichq = eval(n->lft)-1;
  94. if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
  95. return ltab[whichq]->qlen;
  96. return 0;
  97. }
  98. int
  99. q_is_sync(Lextok *n)
  100. { int whichq = eval(n->lft)-1;
  101. if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
  102. return (ltab[whichq]->nslots == 0);
  103. return 0;
  104. }
  105. int
  106. qsend(Lextok *n)
  107. { int whichq = eval(n->lft)-1;
  108. if (whichq == -1)
  109. { printf("Error: sending to an uninitialized chan\n");
  110. whichq = 0;
  111. return 0;
  112. }
  113. if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
  114. { ltab[whichq]->setat = depth;
  115. if (ltab[whichq]->nslots > 0)
  116. return a_snd(ltab[whichq], n);
  117. else
  118. return s_snd(ltab[whichq], n);
  119. }
  120. return 0;
  121. }
  122. int
  123. qrecv(Lextok *n, int full)
  124. { int whichq = eval(n->lft)-1;
  125. if (whichq == -1)
  126. { if (n->sym && !strcmp(n->sym->name, "STDIN"))
  127. { Lextok *m;
  128. if (TstOnly) return 1;
  129. for (m = n->rgt; m; m = m->rgt)
  130. if (m->lft->ntyp != CONST && m->lft->ntyp != EVAL)
  131. { int c = getchar();
  132. (void) setval(m->lft, c);
  133. } else
  134. fatal("invalid use of STDIN", (char *)0);
  135. whichq = 0;
  136. return 1;
  137. }
  138. printf("Error: receiving from an uninitialized chan %s\n",
  139. n->sym?n->sym->name:"");
  140. whichq = 0;
  141. return 0;
  142. }
  143. if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
  144. { ltab[whichq]->setat = depth;
  145. return a_rcv(ltab[whichq], n, full);
  146. }
  147. return 0;
  148. }
  149. static int
  150. sa_snd(Queue *q, Lextok *n) /* sorted asynchronous */
  151. { Lextok *m;
  152. int i, j, k;
  153. int New, Old;
  154. for (i = 0; i < q->qlen; i++)
  155. for (j = 0, m = n->rgt; m && j < q->nflds; m = m->rgt, j++)
  156. { New = cast_val(q->fld_width[j], eval(m->lft), 0);
  157. Old = q->contents[i*q->nflds+j];
  158. if (New == Old) continue;
  159. if (New > Old) break; /* inner loop */
  160. if (New < Old) goto found;
  161. }
  162. found:
  163. for (j = q->qlen-1; j >= i; j--)
  164. for (k = 0; k < q->nflds; k++)
  165. { q->contents[(j+1)*q->nflds+k] =
  166. q->contents[j*q->nflds+k]; /* shift up */
  167. if (k == 0)
  168. q->stepnr[j+1] = q->stepnr[j];
  169. }
  170. return i*q->nflds; /* new q offset */
  171. }
  172. void
  173. typ_ck(int ft, int at, char *s)
  174. {
  175. if ((verbose&32) && ft != at
  176. && (ft == CHAN || at == CHAN))
  177. { char buf[128], tag1[64], tag2[64];
  178. (void) sputtype(tag1, ft);
  179. (void) sputtype(tag2, at);
  180. sprintf(buf, "type-clash in %s, (%s<-> %s)", s, tag1, tag2);
  181. non_fatal("%s", buf);
  182. }
  183. }
  184. static int
  185. a_snd(Queue *q, Lextok *n)
  186. { Lextok *m;
  187. int i = q->qlen*q->nflds; /* q offset */
  188. int j = 0; /* q field# */
  189. if (q->nslots > 0 && q->qlen >= q->nslots)
  190. return m_loss; /* q is full */
  191. if (TstOnly) return 1;
  192. if (n->val) i = sa_snd(q, n); /* sorted insert */
  193. q->stepnr[i/q->nflds] = depth;
  194. for (m = n->rgt; m && j < q->nflds; m = m->rgt, j++)
  195. { int New = eval(m->lft);
  196. q->contents[i+j] = cast_val(q->fld_width[j], New, 0);
  197. if ((verbose&16) && depth >= jumpsteps)
  198. sr_talk(n, New, "Send ", "->", j, q);
  199. typ_ck(q->fld_width[j], Sym_typ(m->lft), "send");
  200. }
  201. if ((verbose&16) && depth >= jumpsteps)
  202. { for (i = j; i < q->nflds; i++)
  203. sr_talk(n, 0, "Send ", "->", i, q);
  204. if (j < q->nflds)
  205. printf("%3d: warning: missing params in send\n",
  206. depth);
  207. if (m)
  208. printf("%3d: warning: too many params in send\n",
  209. depth);
  210. }
  211. q->qlen++;
  212. return 1;
  213. }
  214. static int
  215. a_rcv(Queue *q, Lextok *n, int full)
  216. { Lextok *m;
  217. int i=0, oi, j, k;
  218. extern int Rvous;
  219. if (q->qlen == 0)
  220. return 0; /* q is empty */
  221. try_slot:
  222. /* test executability */
  223. for (m = n->rgt, j=0; m && j < q->nflds; m = m->rgt, j++)
  224. if ((m->lft->ntyp == CONST
  225. && q->contents[i*q->nflds+j] != m->lft->val)
  226. || (m->lft->ntyp == EVAL
  227. && q->contents[i*q->nflds+j] != eval(m->lft->lft)))
  228. { if (n->val == 0 /* fifo recv */
  229. || n->val == 2 /* fifo poll */
  230. || ++i >= q->qlen) /* last slot */
  231. return 0; /* no match */
  232. goto try_slot;
  233. }
  234. if (TstOnly) return 1;
  235. if (verbose&8)
  236. { if (j < q->nflds)
  237. printf("%3d: warning: missing params in next recv\n",
  238. depth);
  239. else if (m)
  240. printf("%3d: warning: too many params in next recv\n",
  241. depth);
  242. }
  243. /* set the fields */
  244. if (Rvous)
  245. { n_rem = n;
  246. q_rem = q;
  247. }
  248. oi = q->stepnr[i];
  249. for (m = n->rgt, j = 0; m && j < q->nflds; m = m->rgt, j++)
  250. { if (columns && !full) /* was columns == 1 */
  251. continue;
  252. if ((verbose&8) && !Rvous && depth >= jumpsteps)
  253. { sr_talk(n, q->contents[i*q->nflds+j],
  254. (full && n->val < 2)?"Recv ":"[Recv] ", "<-", j, q);
  255. }
  256. if (!full)
  257. continue; /* test */
  258. if (m && m->lft->ntyp != CONST && m->lft->ntyp != EVAL)
  259. { (void) setval(m->lft, q->contents[i*q->nflds+j]);
  260. typ_ck(q->fld_width[j], Sym_typ(m->lft), "recv");
  261. }
  262. if (n->val < 2) /* not a poll */
  263. for (k = i; k < q->qlen-1; k++)
  264. { q->contents[k*q->nflds+j] =
  265. q->contents[(k+1)*q->nflds+j];
  266. if (j == 0)
  267. q->stepnr[k] = q->stepnr[k+1];
  268. }
  269. }
  270. if ((!columns || full)
  271. && (verbose&8) && !Rvous && depth >= jumpsteps)
  272. for (i = j; i < q->nflds; i++)
  273. { sr_talk(n, 0,
  274. (full && n->val < 2)?"Recv ":"[Recv] ", "<-", i, q);
  275. }
  276. if (columns == 2 && full && !Rvous && depth >= jumpsteps)
  277. putarrow(oi, depth);
  278. if (full && n->val < 2)
  279. q->qlen--;
  280. return 1;
  281. }
  282. static int
  283. s_snd(Queue *q, Lextok *n)
  284. { Lextok *m;
  285. RunList *rX, *sX = X; /* rX=recvr, sX=sendr */
  286. int i, j = 0; /* q field# */
  287. for (m = n->rgt; m && j < q->nflds; m = m->rgt, j++)
  288. { q->contents[j] = cast_val(q->fld_width[j], eval(m->lft), 0);
  289. typ_ck(q->fld_width[j], Sym_typ(m->lft), "rv-send");
  290. }
  291. q->qlen = 1;
  292. if (!complete_rendez())
  293. { q->qlen = 0;
  294. return 0;
  295. }
  296. if (TstOnly)
  297. { q->qlen = 0;
  298. return 1;
  299. }
  300. q->stepnr[0] = depth;
  301. if ((verbose&16) && depth >= jumpsteps)
  302. { m = n->rgt;
  303. rX = X; X = sX;
  304. for (j = 0; m && j < q->nflds; m = m->rgt, j++)
  305. sr_talk(n, eval(m->lft), "Sent ", "->", j, q);
  306. for (i = j; i < q->nflds; i++)
  307. sr_talk(n, 0, "Sent ", "->", i, q);
  308. if (j < q->nflds)
  309. printf("%3d: warning: missing params in rv-send\n",
  310. depth);
  311. else if (m)
  312. printf("%3d: warning: too many params in rv-send\n",
  313. depth);
  314. X = rX; /* restore receiver's context */
  315. if (!s_trail)
  316. { if (!n_rem || !q_rem)
  317. fatal("cannot happen, s_snd", (char *) 0);
  318. m = n_rem->rgt;
  319. for (j = 0; m && j < q->nflds; m = m->rgt, j++)
  320. { if (m->lft->ntyp != NAME
  321. || strcmp(m->lft->sym->name, "_") != 0)
  322. i = eval(m->lft);
  323. else i = 0;
  324. sr_talk(n_rem,i,"Recv ","<-",j,q_rem);
  325. }
  326. for (i = j; i < q->nflds; i++)
  327. sr_talk(n_rem, 0, "Recv ", "<-", j, q_rem);
  328. if (columns == 2)
  329. putarrow(depth, depth);
  330. }
  331. n_rem = (Lextok *) 0;
  332. q_rem = (Queue *) 0;
  333. }
  334. return 1;
  335. }
  336. void
  337. channm(Lextok *n)
  338. { char lbuf[256];
  339. if (n->sym->type == CHAN)
  340. strcat(Buf, n->sym->name);
  341. else if (n->sym->type == NAME)
  342. strcat(Buf, lookup(n->sym->name)->name);
  343. else if (n->sym->type == STRUCT)
  344. { Symbol *r = n->sym;
  345. if (r->context)
  346. r = findloc(r);
  347. ini_struct(r);
  348. printf("%s", r->name);
  349. struct_name(n->lft, r, 1, lbuf);
  350. strcat(Buf, lbuf);
  351. } else
  352. strcat(Buf, "-");
  353. if (n->lft->lft)
  354. { sprintf(lbuf, "[%d]", eval(n->lft->lft));
  355. strcat(Buf, lbuf);
  356. }
  357. }
  358. static void
  359. difcolumns(Lextok *n, char *tr, int v, int j, Queue *q)
  360. { int cnt = 1; extern int pno;
  361. Lextok *nn = ZN;
  362. if (j == 0)
  363. { Buf[0] = '\0';
  364. channm(n);
  365. strcat(Buf, (strncmp(tr, "Sen", 3))?"?":"!");
  366. } else
  367. strcat(Buf, ",");
  368. if (tr[0] == '[') strcat(Buf, "[");
  369. sr_buf(v, q->fld_width[j] == MTYPE);
  370. if (j == q->nflds - 1)
  371. { int cnr;
  372. if (s_trail) cnr = pno; else cnr = X?X->pid - Have_claim:0;
  373. if (tr[0] == '[') strcat(Buf, "]");
  374. pstext(cnr, Buf);
  375. }
  376. }
  377. static void
  378. docolumns(Lextok *n, char *tr, int v, int j, Queue *q)
  379. { int i;
  380. if (firstrow)
  381. { printf("q\\p");
  382. for (i = 0; i < nproc-nstop - Have_claim; i++)
  383. printf(" %3d", i);
  384. printf("\n");
  385. firstrow = 0;
  386. }
  387. if (j == 0)
  388. { printf("%3d", q->qid);
  389. if (X)
  390. for (i = 0; i < X->pid - Have_claim; i++)
  391. printf(" .");
  392. printf(" ");
  393. Buf[0] = '\0';
  394. channm(n);
  395. printf("%s%c", Buf, (strncmp(tr, "Sen", 3))?'?':'!');
  396. } else
  397. printf(",");
  398. if (tr[0] == '[') printf("[");
  399. sr_mesg(stdout, v, q->fld_width[j] == MTYPE);
  400. if (j == q->nflds - 1)
  401. { if (tr[0] == '[') printf("]");
  402. printf("\n");
  403. }
  404. }
  405. typedef struct QH {
  406. int n;
  407. struct QH *nxt;
  408. } QH;
  409. QH *qh;
  410. void
  411. qhide(int q)
  412. { QH *p = (QH *) emalloc(sizeof(QH));
  413. p->n = q;
  414. p->nxt = qh;
  415. qh = p;
  416. }
  417. int
  418. qishidden(int q)
  419. { QH *p;
  420. for (p = qh; p; p = p->nxt)
  421. if (p->n == q)
  422. return 1;
  423. return 0;
  424. }
  425. static void
  426. sr_talk(Lextok *n, int v, char *tr, char *a, int j, Queue *q)
  427. { char s[64];
  428. if (qishidden(eval(n->lft)))
  429. return;
  430. if (columns)
  431. { if (columns == 2)
  432. difcolumns(n, tr, v, j, q);
  433. else
  434. docolumns(n, tr, v, j, q);
  435. return;
  436. }
  437. if (xspin)
  438. { if ((verbose&4) && tr[0] != '[')
  439. sprintf(s, "(state -)\t[values: %d",
  440. eval(n->lft));
  441. else
  442. sprintf(s, "(state -)\t[%d", eval(n->lft));
  443. if (strncmp(tr, "Sen", 3) == 0)
  444. strcat(s, "!");
  445. else
  446. strcat(s, "?");
  447. } else
  448. { strcpy(s, tr);
  449. }
  450. if (j == 0)
  451. { whoruns(1);
  452. printf("line %3d %s %s",
  453. n->ln, n->fn->name, s);
  454. } else
  455. printf(",");
  456. sr_mesg(stdout, v, q->fld_width[j] == MTYPE);
  457. if (j == q->nflds - 1)
  458. { if (xspin)
  459. { printf("]\n");
  460. if (!(verbose&4)) printf("\n");
  461. return;
  462. }
  463. printf("\t%s queue %d (", a, eval(n->lft));
  464. Buf[0] = '\0';
  465. channm(n);
  466. printf("%s)\n", Buf);
  467. }
  468. fflush(stdout);
  469. }
  470. void
  471. sr_buf(int v, int j)
  472. { int cnt = 1; Lextok *n;
  473. char lbuf[128];
  474. for (n = Mtype; n && j; n = n->rgt, cnt++)
  475. if (cnt == v)
  476. { sprintf(lbuf, "%s", n->lft->sym->name);
  477. strcat(Buf, lbuf);
  478. return;
  479. }
  480. sprintf(lbuf, "%d", v);
  481. strcat(Buf, lbuf);
  482. }
  483. void
  484. sr_mesg(FILE *fd, int v, int j)
  485. { Buf[0] ='\0';
  486. sr_buf(v, j);
  487. fprintf(fd, Buf);
  488. }
  489. void
  490. doq(Symbol *s, int n, RunList *r)
  491. { Queue *q;
  492. int j, k;
  493. if (!s->val) /* uninitialized queue */
  494. return;
  495. for (q = qtab; q; q = q->nxt)
  496. if (q->qid == s->val[n])
  497. { if (xspin > 0
  498. && (verbose&4)
  499. && q->setat < depth)
  500. continue;
  501. if (q->nslots == 0)
  502. continue; /* rv q always empty */
  503. printf("\t\tqueue %d (", q->qid);
  504. if (r)
  505. printf("%s(%d):", r->n->name, r->pid - Have_claim);
  506. if (s->nel != 1)
  507. printf("%s[%d]): ", s->name, n);
  508. else
  509. printf("%s): ", s->name);
  510. for (k = 0; k < q->qlen; k++)
  511. { printf("[");
  512. for (j = 0; j < q->nflds; j++)
  513. { if (j > 0) printf(",");
  514. sr_mesg(stdout, q->contents[k*q->nflds+j],
  515. q->fld_width[j] == MTYPE);
  516. }
  517. printf("]");
  518. }
  519. printf("\n");
  520. break;
  521. }
  522. }
  523. void
  524. nochan_manip(Lextok *p, Lextok *n, int d)
  525. { int e = 1;
  526. if (d == 0 && p->sym && p->sym->type == CHAN)
  527. setaccess(p->sym, ZS, 0, 'L');
  528. if (!n || n->ntyp == LEN || n->ntyp == RUN)
  529. return;
  530. if (n->sym && n->sym->type == CHAN)
  531. { if (d == 1)
  532. fatal("invalid use of chan name", (char *) 0);
  533. else
  534. setaccess(n->sym, ZS, 0, 'V');
  535. }
  536. if (n->ntyp == NAME
  537. || n->ntyp == '.')
  538. e = 0; /* array index or struct element */
  539. nochan_manip(p, n->lft, e);
  540. nochan_manip(p, n->rgt, 1);
  541. }