mesg.c 14 KB

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