xref: /plan9-contrib/sys/src/cmd/spin/sched.c (revision de2caf28f9ba1a56e70be94a699435d36eb50311)
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