1 /***** spin: sched.c *****/
2
3 /*
4 * This file is part of the public release of Spin. It is subject to the
5 * terms in the LICENSE file that is included in this source directory.
6 * Tool documentation is available at http://spinroot.com
7 */
8
9 #include <stdlib.h>
10 #include "spin.h"
11 #include "y.tab.h"
12
13 extern int verbose, s_trail, analyze, no_wrapup;
14 extern char *claimproc, *eventmap, GBuf[];
15 extern Ordered *all_names;
16 extern Symbol *Fname, *context;
17 extern int lineno, nr_errs, dumptab, xspin, jumpsteps, columns;
18 extern int u_sync, Elcnt, interactive, TstOnly, cutoff;
19 extern short has_enabled, has_priority, has_code, replay;
20 extern int limited_vis, product, nclaims, old_priority_rules;
21 extern int old_scope_rules, scope_seq[128], scope_level, has_stdin;
22
23 extern int pc_highest(Lextok *n);
24 extern void putpostlude(void);
25
26 RunList *X_lst = (RunList *) 0;
27 RunList *run_lst = (RunList *) 0;
28 RunList *LastX = (RunList *) 0; /* previous executing proc */
29 ProcList *ready = (ProcList *) 0;
30 Element *LastStep = ZE;
31 int nproc=0, nstop=0, Tval=0, Priority_Sum = 0;
32 int Rvous=0, depth=0, nrRdy=0, MadeChoice;
33 short Have_claim=0, Skip_claim=0;
34
35 static void setlocals(RunList *);
36 static void setparams(RunList *, ProcList *, Lextok *);
37 static void talk(RunList *);
38
39 extern char *which_mtype(const char *);
40
41 void
runnable(ProcList * p,int weight,int noparams)42 runnable(ProcList *p, int weight, int noparams)
43 { RunList *r = (RunList *) emalloc(sizeof(RunList));
44
45 r->n = p->n;
46 r->tn = p->tn;
47 r->b = p->b;
48 r->pid = nproc++ - nstop + Skip_claim;
49 r->priority = weight;
50 p->priority = (unsigned char) weight; /* not quite the best place of course */
51
52 if (!noparams && ((verbose&4) || (verbose&32)))
53 { printf("Starting %s with pid %d",
54 p->n?p->n->name:"--", r->pid);
55 if (has_priority) printf(" priority %d", r->priority);
56 printf("\n");
57 }
58 if (!p->s)
59 fatal("parsing error, no sequence %s",
60 p->n?p->n->name:"--");
61
62 r->pc = huntele(p->s->frst, p->s->frst->status, -1);
63 r->ps = p->s;
64
65 if (p->s->last)
66 p->s->last->status |= ENDSTATE; /* normal end state */
67
68 r->nxt = run_lst;
69 r->prov = p->prov;
70 if (weight < 1 || weight > 255)
71 { fatal("bad process priority, valid range: 1..255", (char *) 0);
72 }
73
74 if (noparams) setlocals(r);
75 Priority_Sum += weight;
76
77 run_lst = r;
78 }
79
80 ProcList *
mk_rdy(Symbol * n,Lextok * p,Sequence * s,int det,Lextok * prov,enum btypes b)81 mk_rdy(Symbol *n, Lextok *p, Sequence *s, int det, Lextok *prov, enum btypes b)
82 /* n=name, p=formals, s=body det=deterministic prov=provided */
83 { ProcList *r = (ProcList *) emalloc(sizeof(ProcList));
84 Lextok *fp, *fpt; int j; extern int Npars;
85
86 r->n = n;
87 r->p = p;
88 r->s = s;
89 r->b = b;
90 r->prov = prov;
91 r->tn = (short) nrRdy++;
92 n->sc = scope_seq[scope_level]; /* scope_level should be 0 */
93
94 if (det != 0 && det != 1)
95 { fprintf(stderr, "spin: bad value for det (cannot happen)\n");
96 }
97 r->det = (unsigned char) det;
98 r->nxt = ready;
99 ready = r;
100
101 for (fp = p, j = 0; fp; fp = fp->rgt)
102 for (fpt = fp->lft; fpt; fpt = fpt->rgt)
103 { j++; /* count # of parameters */
104 }
105 Npars = max(Npars, j);
106
107 return ready;
108 }
109
110 void
check_mtypes(Lextok * pnm,Lextok * args)111 check_mtypes(Lextok *pnm, Lextok *args) /* proctype name, actual params */
112 { ProcList *p = NULL;
113 Lextok *fp, *fpt, *at;
114 char *s, *t;
115
116 if (pnm && pnm->sym)
117 { for (p = ready; p; p = p->nxt)
118 { if (strcmp(pnm->sym->name, p->n->name) == 0)
119 { /* found */
120 break;
121 } } }
122
123 if (!p)
124 { fatal("cannot find proctype '%s'",
125 (pnm && pnm->sym)?pnm->sym->name:"?");
126 }
127
128 for (fp = p->p, at = args; fp; fp = fp->rgt)
129 for (fpt = fp->lft; at && fpt; fpt = fpt->rgt, at = at->rgt)
130 {
131 if (fp->lft->val != MTYPE)
132 { continue;
133 }
134 if (!at->lft->sym)
135 { printf("spin:%d unrecognized mtype value\n",
136 pnm->ln);
137 continue;
138 }
139 s = "_unnamed_";
140 if (fp->lft->sym->mtype_name)
141 { t = fp->lft->sym->mtype_name->name;
142 } else
143 { t = "_unnamed_";
144 }
145 if (at->lft->ntyp != CONST)
146 { fatal("wrong arg type '%s'", at->lft->sym->name);
147 }
148 s = which_mtype(at->lft->sym->name);
149 if (s && strcmp(s, t) != 0)
150 { printf("spin: %s:%d, Error: '%s' is type '%s', but should be type '%s'\n",
151 pnm->fn->name, pnm->ln,
152 at->lft->sym->name, s, t);
153 fatal("wrong arg type '%s'", at->lft->sym->name);
154 } }
155 }
156
157 int
find_maxel(Symbol * s)158 find_maxel(Symbol *s)
159 { ProcList *p;
160
161 for (p = ready; p; p = p->nxt)
162 { if (p->n == s)
163 { return p->s->maxel++;
164 } }
165
166 return Elcnt++;
167 }
168
169 static void
formdump(void)170 formdump(void)
171 { ProcList *p;
172 Lextok *f, *t;
173 int cnt;
174
175 for (p = ready; p; p = p->nxt)
176 { if (!p->p) continue;
177 cnt = -1;
178 for (f = p->p; f; f = f->rgt) /* types */
179 for (t = f->lft; t; t = t->rgt) /* formals */
180 { if (t->ntyp != ',')
181 t->sym->Nid = cnt--; /* overload Nid */
182 else
183 t->lft->sym->Nid = cnt--;
184 }
185 }
186 }
187
188 void
announce(char * w)189 announce(char *w)
190 {
191 if (columns)
192 { extern char GBuf[];
193 extern int firstrow;
194 firstrow = 1;
195 if (columns == 2)
196 { sprintf(GBuf, "%d:%s",
197 run_lst->pid - Have_claim, run_lst->n->name);
198 pstext(run_lst->pid - Have_claim, GBuf);
199 } else
200 { printf("proc %d = %s\n",
201 run_lst->pid - Have_claim, run_lst->n->name);
202 }
203 return;
204 }
205
206 if (dumptab
207 || analyze
208 || product
209 || s_trail
210 || !(verbose&4))
211 return;
212
213 if (w)
214 printf(" 0: proc - (%s) ", w);
215 else
216 whoruns(1);
217 printf("creates proc %2d (%s)",
218 run_lst->pid - Have_claim,
219 run_lst->n->name);
220 if (run_lst->priority > 1)
221 printf(" priority %d", run_lst->priority);
222 printf("\n");
223 }
224
225 #ifndef MAXP
226 #define MAXP 255 /* matches max nr of processes in verifier */
227 #endif
228
229 int
enable(Lextok * m)230 enable(Lextok *m)
231 { ProcList *p;
232 Symbol *s = m->sym; /* proctype name */
233 Lextok *n = m->lft; /* actual parameters */
234
235 if (m->val < 1)
236 { m->val = 1; /* minimum priority */
237 }
238 for (p = ready; p; p = p->nxt)
239 { if (strcmp(s->name, p->n->name) == 0)
240 { if (nproc-nstop >= MAXP)
241 { printf("spin: too many processes (%d max)\n", MAXP);
242 break;
243 }
244 runnable(p, m->val, 0);
245 announce((char *) 0);
246 setparams(run_lst, p, n);
247 setlocals(run_lst); /* after setparams */
248 check_mtypes(m, m->lft);
249 return run_lst->pid - Have_claim + Skip_claim; /* effective simu pid */
250 } }
251 return 0; /* process not found */
252 }
253
254 void
check_param_count(int i,Lextok * m)255 check_param_count(int i, Lextok *m)
256 { ProcList *p;
257 Symbol *s = m->sym; /* proctype name */
258 Lextok *f, *t; /* formal pars */
259 int cnt = 0;
260
261 for (p = ready; p; p = p->nxt)
262 { if (strcmp(s->name, p->n->name) == 0)
263 { if (m->lft) /* actual param list */
264 { lineno = m->lft->ln;
265 Fname = m->lft->fn;
266 }
267 for (f = p->p; f; f = f->rgt) /* one type at a time */
268 for (t = f->lft; t; t = t->rgt) /* count formal params */
269 { cnt++;
270 }
271 if (i != cnt)
272 { printf("spin: saw %d parameters, expected %d\n", i, cnt);
273 non_fatal("wrong number of parameters", "");
274 }
275 break;
276 } }
277 }
278
279 void
start_claim(int n)280 start_claim(int n)
281 { ProcList *p;
282 RunList *r, *q = (RunList *) 0;
283
284 for (p = ready; p; p = p->nxt)
285 if (p->tn == n && p->b == N_CLAIM)
286 { runnable(p, 1, 1);
287 goto found;
288 }
289 printf("spin: couldn't find claim %d (ignored)\n", n);
290 if (verbose&32)
291 for (p = ready; p; p = p->nxt)
292 printf("\t%d = %s\n", p->tn, p->n->name);
293
294 Skip_claim = 1;
295 goto done;
296 found:
297 /* move claim to far end of runlist, and reassign it pid 0 */
298 if (columns == 2)
299 { extern char GBuf[];
300 depth = 0;
301 sprintf(GBuf, "%d:%s", 0, p->n->name);
302 pstext(0, GBuf);
303 for (r = run_lst; r; r = r->nxt)
304 { if (r->b != N_CLAIM)
305 { sprintf(GBuf, "%d:%s", r->pid+1, r->n->name);
306 pstext(r->pid+1, GBuf);
307 } } }
308
309 if (run_lst->pid == 0) return; /* it is the first process started */
310
311 q = run_lst; run_lst = run_lst->nxt;
312 q->pid = 0; q->nxt = (RunList *) 0; /* remove */
313 done:
314 Have_claim = 1;
315 for (r = run_lst; r; r = r->nxt)
316 { r->pid = r->pid+Have_claim; /* adjust */
317 if (!r->nxt)
318 { r->nxt = q;
319 break;
320 } }
321 }
322
323 int
f_pid(char * n)324 f_pid(char *n)
325 { RunList *r;
326 int rval = -1;
327
328 for (r = run_lst; r; r = r->nxt)
329 if (strcmp(n, r->n->name) == 0)
330 { if (rval >= 0)
331 { printf("spin: remote ref to proctype %s, ", n);
332 printf("has more than one match: %d and %d\n",
333 rval, r->pid);
334 } else
335 rval = r->pid;
336 }
337 return rval;
338 }
339
340 void
wrapup(int fini)341 wrapup(int fini)
342 {
343 limited_vis = 0;
344 if (columns)
345 { if (columns == 2) putpostlude();
346 if (!no_wrapup)
347 printf("-------------\nfinal state:\n-------------\n");
348 }
349 if (no_wrapup)
350 goto short_cut;
351 if (nproc != nstop)
352 { int ov = verbose;
353 printf("#processes: %d\n", nproc-nstop - Have_claim + Skip_claim);
354 verbose &= ~4;
355 dumpglobals();
356 verbose = ov;
357 verbose &= ~1; /* no more globals */
358 verbose |= 32; /* add process states */
359 for (X_lst = run_lst; X_lst; X_lst = X_lst->nxt)
360 talk(X_lst);
361 verbose = ov; /* restore */
362 }
363 printf("%d process%s created\n",
364 nproc - Have_claim + Skip_claim,
365 (xspin || nproc!=1)?"es":"");
366 short_cut:
367 if (s_trail || xspin) alldone(0); /* avoid an abort from xspin */
368 if (fini) alldone(1);
369 }
370
371 static char is_blocked[256];
372
373 static int
p_blocked(int p)374 p_blocked(int p)
375 { int i, j;
376
377 is_blocked[p%256] = 1;
378 for (i = j = 0; i < nproc - nstop; i++)
379 j += is_blocked[i];
380 if (j >= nproc - nstop)
381 { memset(is_blocked, 0, 256);
382 return 1;
383 }
384 return 0;
385 }
386
387 static Element *
silent_moves(Element * e)388 silent_moves(Element *e)
389 { Element *f;
390
391 if (e->n)
392 switch (e->n->ntyp) {
393 case GOTO:
394 if (Rvous) break;
395 f = get_lab(e->n, 1);
396 cross_dsteps(e->n, f->n);
397 return f; /* guard against goto cycles */
398 case UNLESS:
399 return silent_moves(e->sub->this->frst);
400 case NON_ATOMIC:
401 case ATOMIC:
402 case D_STEP:
403 e->n->sl->this->last->nxt = e->nxt;
404 return silent_moves(e->n->sl->this->frst);
405 case '.':
406 return silent_moves(e->nxt);
407 }
408 return e;
409 }
410
411 static int
x_can_run(void)412 x_can_run(void) /* the currently selected process in X_lst can run */
413 {
414 if (X_lst->prov && !eval(X_lst->prov))
415 {
416 if (0) printf("pid %d cannot run: not provided\n", X_lst->pid);
417 return 0;
418 }
419 if (has_priority && !old_priority_rules)
420 { Lextok *n = nn(ZN, CONST, ZN, ZN);
421 n->val = X_lst->pid;
422 if (0) printf("pid %d %s run (priority)\n", X_lst->pid, pc_highest(n)?"can":"cannot");
423 return pc_highest(n);
424 }
425 if (0) printf("pid %d can run\n", X_lst->pid);
426 return 1;
427 }
428
429 static RunList *
pickproc(RunList * Y)430 pickproc(RunList *Y)
431 { SeqList *z; Element *has_else;
432 short Choices[256];
433 int j, k, nr_else = 0;
434
435 if (nproc <= nstop+1)
436 { X_lst = run_lst;
437 return NULL;
438 }
439 if (!interactive || depth < jumpsteps)
440 { if (has_priority && !old_priority_rules) /* new 6.3.2 */
441 { j = Rand()%(nproc-nstop);
442 for (X_lst = run_lst; X_lst; X_lst = X_lst->nxt)
443 { if (j-- <= 0)
444 break;
445 }
446 if (X_lst == NULL)
447 { fatal("unexpected, pickproc", (char *)0);
448 }
449 j = nproc - nstop;
450 while (j-- > 0)
451 { if (x_can_run())
452 { Y = X_lst;
453 break;
454 }
455 X_lst = (X_lst->nxt)?X_lst->nxt:run_lst;
456 }
457 return Y;
458 }
459 if (Priority_Sum < nproc-nstop)
460 fatal("cannot happen - weights", (char *)0);
461 j = (int) Rand()%Priority_Sum;
462
463 while (j - X_lst->priority >= 0)
464 { j -= X_lst->priority;
465 Y = X_lst;
466 X_lst = X_lst->nxt;
467 if (!X_lst) { Y = NULL; X_lst = run_lst; }
468 }
469
470 } else
471 { int only_choice = -1;
472 int no_choice = 0, proc_no_ch, proc_k;
473
474 Tval = 0; /* new 4.2.6 */
475 try_again: printf("Select a statement\n");
476 try_more: for (X_lst = run_lst, k = 1; X_lst; X_lst = X_lst->nxt)
477 { if (X_lst->pid > 255) break;
478
479 Choices[X_lst->pid] = (short) k;
480
481 if (!X_lst->pc || !x_can_run())
482 { if (X_lst == run_lst)
483 Choices[X_lst->pid] = 0;
484 continue;
485 }
486 X_lst->pc = silent_moves(X_lst->pc);
487 if (!X_lst->pc->sub && X_lst->pc->n)
488 { int unex;
489 unex = !Enabled0(X_lst->pc);
490 if (unex)
491 no_choice++;
492 else
493 only_choice = k;
494 if (!xspin && unex && !(verbose&32))
495 { k++;
496 continue;
497 }
498 printf("\tchoice %d: ", k++);
499 p_talk(X_lst->pc, 0);
500 if (unex)
501 printf(" unexecutable,");
502 printf(" [");
503 comment(stdout, X_lst->pc->n, 0);
504 if (X_lst->pc->esc) printf(" + Escape");
505 printf("]\n");
506 } else {
507 has_else = ZE;
508 proc_no_ch = no_choice;
509 proc_k = k;
510 for (z = X_lst->pc->sub, j=0; z; z = z->nxt)
511 { Element *y = silent_moves(z->this->frst);
512 int unex;
513 if (!y) continue;
514
515 if (y->n->ntyp == ELSE)
516 { has_else = (Rvous)?ZE:y;
517 nr_else = k++;
518 continue;
519 }
520
521 unex = !Enabled0(y);
522 if (unex)
523 no_choice++;
524 else
525 only_choice = k;
526 if (!xspin && unex && !(verbose&32))
527 { k++;
528 continue;
529 }
530 printf("\tchoice %d: ", k++);
531 p_talk(X_lst->pc, 0);
532 if (unex)
533 printf(" unexecutable,");
534 printf(" [");
535 comment(stdout, y->n, 0);
536 printf("]\n");
537 }
538 if (has_else)
539 { if (no_choice-proc_no_ch >= (k-proc_k)-1)
540 { only_choice = nr_else;
541 printf("\tchoice %d: ", nr_else);
542 p_talk(X_lst->pc, 0);
543 printf(" [else]\n");
544 } else
545 { no_choice++;
546 printf("\tchoice %d: ", nr_else);
547 p_talk(X_lst->pc, 0);
548 printf(" unexecutable, [else]\n");
549 } }
550 } }
551 X_lst = run_lst;
552 if (k - no_choice < 2 && Tval == 0)
553 { Tval = 1;
554 no_choice = 0; only_choice = -1;
555 goto try_more;
556 }
557 if (xspin)
558 printf("Make Selection %d\n\n", k-1);
559 else
560 { if (k - no_choice < 2)
561 { printf("no executable choices\n");
562 alldone(0);
563 }
564 printf("Select [1-%d]: ", k-1);
565 }
566 if (!xspin && k - no_choice == 2)
567 { printf("%d\n", only_choice);
568 j = only_choice;
569 } else
570 { char buf[256];
571 fflush(stdout);
572 if (scanf("%64s", buf) == 0)
573 { printf("\tno input\n");
574 goto try_again;
575 }
576 j = -1;
577 if (isdigit((int) buf[0]))
578 j = atoi(buf);
579 else
580 { if (buf[0] == 'q')
581 alldone(0);
582 }
583 if (j < 1 || j >= k)
584 { printf("\tchoice is outside range\n");
585 goto try_again;
586 } }
587 MadeChoice = 0;
588 Y = NULL;
589 for (X_lst = run_lst; X_lst; Y = X_lst, X_lst = X_lst->nxt)
590 { if (!X_lst->nxt
591 || X_lst->nxt->pid > 255
592 || j < Choices[X_lst->nxt->pid])
593 {
594 MadeChoice = 1+j-Choices[X_lst->pid];
595 break;
596 } }
597 }
598 return Y;
599 }
600
601 void
multi_claims(void)602 multi_claims(void)
603 { ProcList *p, *q = NULL;
604
605 if (nclaims > 1)
606 { printf(" the model contains %d never claims:", nclaims);
607 for (p = ready; p; p = p->nxt)
608 { if (p->b == N_CLAIM)
609 { printf("%s%s", q?", ":" ", p->n->name);
610 q = p;
611 } }
612 printf("\n");
613 printf(" only one claim is used in a verification run\n");
614 printf(" choose which one with ./pan -a -N name (defaults to -N %s)\n",
615 q?q->n->name:"--");
616 printf(" or use e.g.: spin -search -ltl %s %s\n",
617 q?q->n->name:"--", Fname?Fname->name:"filename");
618 }
619 }
620
621 void
sched(void)622 sched(void)
623 { Element *e;
624 RunList *Y = NULL; /* previous process in run queue */
625 RunList *oX;
626 int go, notbeyond = 0;
627 #ifdef PC
628 int bufmax = 100;
629 #endif
630 if (dumptab)
631 { formdump();
632 symdump();
633 dumplabels();
634 return;
635 }
636 if (has_code && !analyze)
637 { printf("spin: warning: c_code fragments remain uninterpreted\n");
638 printf(" in random simulations with spin; use ./pan -r instead\n");
639 }
640
641 if (has_enabled && u_sync > 0)
642 { printf("spin: error, cannot use 'enabled()' in ");
643 printf("models with synchronous channels.\n");
644 nr_errs++;
645 }
646 if (product)
647 { sync_product();
648 alldone(0);
649 }
650 if (analyze && (!replay || has_code))
651 { gensrc();
652 multi_claims();
653 return;
654 }
655 if (replay && !has_code)
656 { return;
657 }
658 if (s_trail)
659 { match_trail();
660 return;
661 }
662
663 if (claimproc)
664 printf("warning: never claim not used in random simulation\n");
665 if (eventmap)
666 printf("warning: trace assertion not used in random simulation\n");
667
668 X_lst = run_lst;
669 Y = pickproc(Y);
670
671 while (X_lst)
672 { context = X_lst->n;
673 if (X_lst->pc && X_lst->pc->n)
674 { lineno = X_lst->pc->n->ln;
675 Fname = X_lst->pc->n->fn;
676 }
677 if (cutoff > 0 && depth >= cutoff)
678 { printf("-------------\n");
679 printf("depth-limit (-u%d steps) reached\n", cutoff);
680 break;
681 }
682 #ifdef PC
683 if (xspin && !interactive && --bufmax <= 0)
684 { int c; /* avoid buffer overflow on pc's */
685 printf("spin: type return to proceed\n");
686 fflush(stdout);
687 c = getc(stdin);
688 if (c == 'q') wrapup(0);
689 bufmax = 100;
690 }
691 #endif
692 depth++; LastStep = ZE;
693 oX = X_lst; /* a rendezvous could change it */
694 go = 1;
695 if (X_lst->pc
696 && !(X_lst->pc->status & D_ATOM)
697 && !x_can_run())
698 { if (!xspin && ((verbose&32) || (verbose&4)))
699 { p_talk(X_lst->pc, 1);
700 printf("\t<<Not Enabled>>\n");
701 }
702 go = 0;
703 }
704 if (go && (e = eval_sub(X_lst->pc)))
705 { if (depth >= jumpsteps
706 && ((verbose&32) || (verbose&4)))
707 { if (X_lst == oX)
708 if (!(e->status & D_ATOM) || (verbose&32)) /* no talking in d_steps */
709 { if (!LastStep) LastStep = X_lst->pc;
710 /* A. Tanaka, changed order */
711 p_talk(LastStep, 1);
712 printf(" [");
713 comment(stdout, LastStep->n, 0);
714 printf("]\n");
715 }
716 if (verbose&1) dumpglobals();
717 if (verbose&2) dumplocal(X_lst, 0);
718
719 if (!(e->status & D_ATOM))
720 if (xspin)
721 printf("\n");
722 }
723 if (oX != X_lst
724 || (X_lst->pc->status & (ATOM|D_ATOM))) /* new 5.0 */
725 { e = silent_moves(e);
726 notbeyond = 0;
727 }
728 oX->pc = e; LastX = X_lst;
729
730 if (!interactive) Tval = 0;
731 memset(is_blocked, 0, 256);
732
733 if (X_lst->pc && (X_lst->pc->status & (ATOM|L_ATOM))
734 && (notbeyond == 0 || oX != X_lst))
735 { if ((X_lst->pc->status & L_ATOM))
736 notbeyond = 1;
737 continue; /* no process switch */
738 }
739 } else
740 { depth--;
741 if (oX->pc && (oX->pc->status & D_ATOM))
742 { non_fatal("stmnt in d_step blocks", (char *)0);
743 }
744 if (X_lst->pc
745 && X_lst->pc->n
746 && X_lst->pc->n->ntyp == '@'
747 && X_lst->pid == (nproc-nstop-1))
748 { if (X_lst != run_lst && Y != NULL)
749 Y->nxt = X_lst->nxt;
750 else
751 run_lst = X_lst->nxt;
752 nstop++;
753 Priority_Sum -= X_lst->priority;
754 if (verbose&4)
755 { whoruns(1);
756 dotag(stdout, "terminates\n");
757 }
758 LastX = X_lst;
759 if (!interactive) Tval = 0;
760 if (nproc == nstop) break;
761 memset(is_blocked, 0, 256);
762 /* proc X_lst is no longer in runlist */
763 X_lst = (X_lst->nxt) ? X_lst->nxt : run_lst;
764 } else
765 { if (p_blocked(X_lst->pid))
766 { if (Tval && !has_stdin)
767 { break;
768 }
769 if (!Tval && depth >= jumpsteps)
770 { oX = X_lst;
771 X_lst = (RunList *) 0; /* to suppress indent */
772 dotag(stdout, "timeout\n");
773 X_lst = oX;
774 Tval = 1;
775 } } } }
776
777 if (!run_lst || !X_lst) break; /* new 5.0 */
778
779 Y = pickproc(X_lst);
780 notbeyond = 0;
781 }
782 context = ZS;
783 wrapup(0);
784 }
785
786 int
complete_rendez(void)787 complete_rendez(void)
788 { RunList *orun = X_lst, *tmp;
789 Element *s_was = LastStep;
790 Element *e;
791 int j, ointer = interactive;
792
793 if (s_trail)
794 return 1;
795 if (orun->pc->status & D_ATOM)
796 fatal("rv-attempt in d_step sequence", (char *)0);
797 Rvous = 1;
798 interactive = 0;
799
800 j = (int) Rand()%Priority_Sum; /* randomize start point */
801 X_lst = run_lst;
802 while (j - X_lst->priority >= 0)
803 { j -= X_lst->priority;
804 X_lst = X_lst->nxt;
805 if (!X_lst) X_lst = run_lst;
806 }
807 for (j = nproc - nstop; j > 0; j--)
808 { if (X_lst != orun
809 && (!X_lst->prov || eval(X_lst->prov))
810 && (e = eval_sub(X_lst->pc)))
811 { if (TstOnly)
812 { X_lst = orun;
813 Rvous = 0;
814 goto out;
815 }
816 if ((verbose&32) || (verbose&4))
817 { tmp = orun; orun = X_lst; X_lst = tmp;
818 if (!s_was) s_was = X_lst->pc;
819 p_talk(s_was, 1);
820 printf(" [");
821 comment(stdout, s_was->n, 0);
822 printf("]\n");
823 tmp = orun; /* orun = X_lst; */ X_lst = tmp;
824 if (!LastStep) LastStep = X_lst->pc;
825 p_talk(LastStep, 1);
826 printf(" [");
827 comment(stdout, LastStep->n, 0);
828 printf("]\n");
829 }
830 Rvous = 0; /* before silent_moves */
831 X_lst->pc = silent_moves(e);
832 out: interactive = ointer;
833 return 1;
834 }
835
836 X_lst = X_lst->nxt;
837 if (!X_lst) X_lst = run_lst;
838 }
839 Rvous = 0;
840 X_lst = orun;
841 interactive = ointer;
842 return 0;
843 }
844
845 /***** Runtime - Local Variables *****/
846
847 static void
addsymbol(RunList * r,Symbol * s)848 addsymbol(RunList *r, Symbol *s)
849 { Symbol *t;
850 int i;
851
852 for (t = r->symtab; t; t = t->next)
853 if (strcmp(t->name, s->name) == 0
854 && (old_scope_rules
855 || strcmp((const char *)t->bscp, (const char *)s->bscp) == 0))
856 return; /* it's already there */
857
858 t = (Symbol *) emalloc(sizeof(Symbol));
859 t->name = s->name;
860 t->type = s->type;
861 t->hidden = s->hidden;
862 t->isarray = s->isarray;
863 t->nbits = s->nbits;
864 t->nel = s->nel;
865 t->ini = s->ini;
866 t->setat = depth;
867 t->context = r->n;
868
869 t->bscp = (unsigned char *) emalloc(strlen((const char *)s->bscp)+1);
870 strcpy((char *)t->bscp, (const char *)s->bscp);
871
872 if (s->type != STRUCT)
873 { if (s->val) /* if already initialized, copy info */
874 { t->val = (int *) emalloc(s->nel*sizeof(int));
875 for (i = 0; i < s->nel; i++)
876 t->val[i] = s->val[i];
877 } else
878 { (void) checkvar(t, 0); /* initialize it */
879 }
880 } else
881 { if (s->Sval)
882 fatal("saw preinitialized struct %s", s->name);
883 t->Slst = s->Slst;
884 t->Snm = s->Snm;
885 t->owner = s->owner;
886 /* t->context = r->n; */
887 }
888 t->next = r->symtab; /* add it */
889 r->symtab = t;
890 }
891
892 static void
setlocals(RunList * r)893 setlocals(RunList *r)
894 { Ordered *walk;
895 Symbol *sp;
896 RunList *oX = X_lst;
897
898 X_lst = r;
899 for (walk = all_names; walk; walk = walk->next)
900 { sp = walk->entry;
901 if (sp
902 && sp->context
903 && strcmp(sp->context->name, r->n->name) == 0
904 && sp->Nid >= 0
905 && (sp->type == UNSIGNED
906 || sp->type == BIT
907 || sp->type == MTYPE
908 || sp->type == BYTE
909 || sp->type == CHAN
910 || sp->type == SHORT
911 || sp->type == INT
912 || sp->type == STRUCT))
913 { if (!findloc(sp))
914 non_fatal("setlocals: cannot happen '%s'",
915 sp->name);
916 }
917 }
918 X_lst = oX;
919 }
920
921 static void
oneparam(RunList * r,Lextok * t,Lextok * a,ProcList * p)922 oneparam(RunList *r, Lextok *t, Lextok *a, ProcList *p)
923 { int k; int at, ft;
924 RunList *oX = X_lst;
925
926 if (!a)
927 fatal("missing actual parameters: '%s'", p->n->name);
928 if (t->sym->nel > 1 || t->sym->isarray)
929 fatal("array in parameter list, %s", t->sym->name);
930 k = eval(a->lft);
931
932 at = Sym_typ(a->lft);
933 X_lst = r; /* switch context */
934 ft = Sym_typ(t);
935
936 if (at != ft && (at == CHAN || ft == CHAN))
937 { char buf[256], tag1[64], tag2[64];
938 (void) sputtype(tag1, ft);
939 (void) sputtype(tag2, at);
940 sprintf(buf, "type-clash in params of %s(..), (%s<-> %s)",
941 p->n->name, tag1, tag2);
942 non_fatal("%s", buf);
943 }
944 t->ntyp = NAME;
945 addsymbol(r, t->sym);
946 (void) setval(t, k);
947
948 X_lst = oX;
949 }
950
951 static void
setparams(RunList * r,ProcList * p,Lextok * q)952 setparams(RunList *r, ProcList *p, Lextok *q)
953 { Lextok *f, *a; /* formal and actual pars */
954 Lextok *t; /* list of pars of 1 type */
955
956 if (q)
957 { lineno = q->ln;
958 Fname = q->fn;
959 }
960 for (f = p->p, a = q; f; f = f->rgt) /* one type at a time */
961 for (t = f->lft; t; t = t->rgt, a = (a)?a->rgt:a)
962 { if (t->ntyp != ',')
963 oneparam(r, t, a, p); /* plain var */
964 else
965 oneparam(r, t->lft, a, p); /* expanded struct */
966 }
967 }
968
969 Symbol *
findloc(Symbol * s)970 findloc(Symbol *s)
971 { Symbol *r;
972
973 if (!X_lst)
974 { /* fatal("error, cannot eval '%s' (no proc)", s->name); */
975 return ZS;
976 }
977 for (r = X_lst->symtab; r; r = r->next)
978 { if (strcmp(r->name, s->name) == 0
979 && (old_scope_rules
980 || strcmp((const char *)r->bscp, (const char *)s->bscp) == 0))
981 { break;
982 } }
983 if (!r)
984 { addsymbol(X_lst, s);
985 r = X_lst->symtab;
986 }
987 return r;
988 }
989
990 int
in_bound(Symbol * r,int n)991 in_bound(Symbol *r, int n)
992 {
993 if (!r) return 0;
994
995 if (n >= r->nel || n < 0)
996 { printf("spin: indexing %s[%d] - size is %d\n",
997 r->name, n, r->nel);
998 non_fatal("indexing array \'%s\'", r->name);
999 return 0;
1000 }
1001 return 1;
1002 }
1003
1004 int
getlocal(Lextok * sn)1005 getlocal(Lextok *sn)
1006 { Symbol *r, *s = sn->sym;
1007 int n = eval(sn->lft);
1008
1009 r = findloc(s);
1010 if (r && r->type == STRUCT)
1011 return Rval_struct(sn, r, 1); /* 1 = check init */
1012 if (in_bound(r, n))
1013 return cast_val(r->type, r->val[n], r->nbits);
1014 return 0;
1015 }
1016
1017 int
setlocal(Lextok * p,int m)1018 setlocal(Lextok *p, int m)
1019 { Symbol *r = findloc(p->sym);
1020 int n = eval(p->lft);
1021
1022 if (in_bound(r, n))
1023 { if (r->type == STRUCT)
1024 (void) Lval_struct(p, r, 1, m); /* 1 = check init */
1025 else
1026 {
1027 #if 0
1028 if (r->nbits > 0)
1029 m = (m & ((1<<r->nbits)-1));
1030 r->val[n] = m;
1031 #else
1032 r->val[n] = cast_val(r->type, m, r->nbits);
1033 #endif
1034 r->setat = depth;
1035 } }
1036
1037 return 1;
1038 }
1039
1040 void
whoruns(int lnr)1041 whoruns(int lnr)
1042 { if (!X_lst) return;
1043
1044 if (lnr) printf("%3d: ", depth);
1045 printf("proc ");
1046 if (Have_claim && X_lst->pid == 0)
1047 printf(" -");
1048 else
1049 printf("%2d", X_lst->pid - Have_claim);
1050 if (old_priority_rules)
1051 { printf(" (%s) ", X_lst->n->name);
1052 } else
1053 { printf(" (%s:%d) ", X_lst->n->name, X_lst->priority);
1054 }
1055 }
1056
1057 static void
talk(RunList * r)1058 talk(RunList *r)
1059 {
1060 if ((verbose&32) || (verbose&4))
1061 { p_talk(r->pc, 1);
1062 printf("\n");
1063 if (verbose&1) dumpglobals();
1064 if (verbose&2) dumplocal(r, 1);
1065 }
1066 }
1067
1068 void
p_talk(Element * e,int lnr)1069 p_talk(Element *e, int lnr)
1070 { static int lastnever = -1;
1071 static char nbuf[128];
1072 int newnever = -1;
1073
1074 if (e && e->n)
1075 newnever = e->n->ln;
1076
1077 if (Have_claim && X_lst && X_lst->pid == 0
1078 && lastnever != newnever && e)
1079 { if (xspin)
1080 { printf("MSC: ~G line %d\n", newnever);
1081 #if 0
1082 printf("%3d: proc - (NEVER) line %d \"never\" ",
1083 depth, newnever);
1084 printf("(state 0)\t[printf('MSC: never\\\\n')]\n");
1085 } else
1086 { printf("%3d: proc - (NEVER) line %d \"never\"\n",
1087 depth, newnever);
1088 #endif
1089 }
1090 lastnever = newnever;
1091 }
1092
1093 whoruns(lnr);
1094 if (e)
1095 { if (e->n)
1096 { char *ptr = e->n->fn->name;
1097 char *qtr = nbuf;
1098 while (*ptr != '\0')
1099 { if (*ptr != '"')
1100 { *qtr++ = *ptr;
1101 }
1102 ptr++;
1103 }
1104 *qtr = '\0';
1105 } else
1106 { strcpy(nbuf, "-");
1107 }
1108 printf("%s:%d (state %d)",
1109 nbuf,
1110 e->n?e->n->ln:-1,
1111 e->seqno);
1112 if (!xspin
1113 && ((e->status&ENDSTATE) || has_lab(e, 2))) /* 2=end */
1114 { printf(" <valid end state>");
1115 }
1116 }
1117 }
1118
1119 int
remotelab(Lextok * n)1120 remotelab(Lextok *n)
1121 { int i;
1122
1123 lineno = n->ln;
1124 Fname = n->fn;
1125 if (n->sym->type != 0 && n->sym->type != LABEL)
1126 { printf("spin: error, type: %d\n", n->sym->type);
1127 fatal("not a labelname: '%s'", n->sym->name);
1128 }
1129 if (n->indstep >= 0)
1130 { fatal("remote ref to label '%s' inside d_step",
1131 n->sym->name);
1132 }
1133 if ((i = find_lab(n->sym, n->lft->sym, 1)) == 0) /* remotelab */
1134 { fatal("unknown labelname: %s", n->sym->name);
1135 }
1136 return i;
1137 }
1138
1139 int
remotevar(Lextok * n)1140 remotevar(Lextok *n)
1141 { int prno, i, added=0;
1142 RunList *Y, *oX;
1143 Lextok *onl;
1144 Symbol *os;
1145
1146 lineno = n->ln;
1147 Fname = n->fn;
1148
1149 if (!n->lft->lft)
1150 prno = f_pid(n->lft->sym->name);
1151 else
1152 { prno = eval(n->lft->lft); /* pid - can cause recursive call */
1153 #if 0
1154 if (n->lft->lft->ntyp == CONST) /* user-guessed pid */
1155 #endif
1156 { prno += Have_claim;
1157 added = Have_claim;
1158 } }
1159
1160 if (prno < 0)
1161 { return 0; /* non-existing process */
1162 }
1163 #if 0
1164 i = nproc - nstop;
1165 for (Y = run_lst; Y; Y = Y->nxt)
1166 { --i;
1167 printf(" %s: i=%d, prno=%d, ->pid=%d\n", Y->n->name, i, prno, Y->pid);
1168 }
1169 #endif
1170 i = nproc - nstop + Skip_claim; /* 6.0: added Skip_claim */
1171 for (Y = run_lst; Y; Y = Y->nxt)
1172 if (--i == prno)
1173 { if (strcmp(Y->n->name, n->lft->sym->name) != 0)
1174 { printf("spin: remote reference error on '%s[%d]'\n",
1175 n->lft->sym->name, prno-added);
1176 non_fatal("refers to wrong proctype '%s'", Y->n->name);
1177 }
1178 if (strcmp(n->sym->name, "_p") == 0)
1179 { if (Y->pc)
1180 { return Y->pc->seqno;
1181 }
1182 /* harmless, can only happen with -t */
1183 return 0;
1184 }
1185
1186 /* check remote variables */
1187 oX = X_lst;
1188 X_lst = Y;
1189
1190 onl = n->lft;
1191 n->lft = n->rgt;
1192
1193 os = n->sym;
1194 if (!n->sym->context)
1195 { n->sym->context = Y->n;
1196 }
1197 { int rs = old_scope_rules;
1198 old_scope_rules = 1; /* 6.4.0 */
1199 n->sym = findloc(n->sym);
1200 old_scope_rules = rs;
1201 }
1202 i = getval(n);
1203
1204 n->sym = os;
1205 n->lft = onl;
1206 X_lst = oX;
1207 return i;
1208 }
1209 printf("remote ref: %s[%d] ", n->lft->sym->name, prno-added);
1210 non_fatal("%s not found", n->sym->name);
1211 printf("have only:\n");
1212 i = nproc - nstop - 1;
1213 for (Y = run_lst; Y; Y = Y->nxt, i--)
1214 if (!strcmp(Y->n->name, n->lft->sym->name))
1215 printf("\t%d\t%s\n", i, Y->n->name);
1216
1217 return 0;
1218 }
1219