mesg.c 13 KB

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