xref: /titanic_44/usr/src/cmd/fm/modules/common/eversholt/itree.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * itree.c -- instance tree creation and manipulation
27  *
28  * this module provides the instance tree
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <stdio.h>
34 #include <ctype.h>
35 #include <string.h>
36 #include <strings.h>
37 #include "alloc.h"
38 #include "out.h"
39 #include "stable.h"
40 #include "literals.h"
41 #include "lut.h"
42 #include "tree.h"
43 #include "ptree.h"
44 #include "itree.h"
45 #include "ipath.h"
46 #include "eval.h"
47 #include "config.h"
48 
49 /*
50  * struct info contains the state we keep when expanding a prop statement
51  * as part of constructing the instance tree.  state kept in struct info
52  * is the non-recursive stuff -- the stuff that doesn't need to be on
53  * the stack.  the rest of the state that is passed between all the
54  * mutually recursive functions, is required to be on the stack since
55  * we need to backtrack and recurse as we do the instance tree construction.
56  */
57 struct info {
58 	struct lut *lut;
59 	struct node *anp;	/* arrow np */
60 	struct lut *ex;		/* dictionary of explicit iterators */
61 	struct config *croot;
62 } Ninfo;
63 
64 /*
65  * struct wildcardinfo is used to track wildcarded portions of paths.
66  *
67  * for example, if the epname of an event is "c/d" and the path "a/b/c/d"
68  * exists, the wildcard path ewname is filled in with the path "a/b".  when
69  * matching is done, epname is temporarily replaced with the concatenation
70  * of ewname and epname.  cpstart is set to the (struct config *)
71  * corresponding to component "c".
72  *
73  * a linked list of these structs is used to track the expansion of each
74  * event node as it is processed in vmatch() --> vmatch_event() calls.
75  */
76 struct wildcardinfo {
77 	struct node *nptop;		/* event node fed to vmatch */
78 	struct node *oldepname;		/* epname without the wildcard part */
79 	enum status {
80 		WC_UNDEFINED,		/* struct is not yet initialized */
81 		WC_UNDERCONSTRUCTION,	/* wildcard path not yet done */
82 		WC_COMPLETE,		/* wildcard path done and is in use */
83 		WC_REFERENCING		/* use another node's wildcard path */
84 	} s;
85 	struct wildcardpath {
86 		struct node *ewname;	/* wildcard path */
87 		struct config *cpstart;	/* starting cp node for oldepname */
88 		struct config *cpforcedwc;	/* forced wildcard for this */
89 		int refcount;		/* number of event nodes using this */
90 	} *p;
91 	struct wildcardinfo *next;
92 };
93 
94 static void vmatch(struct info *infop, struct node *np,
95     struct node *lnp, struct node *anp, struct wildcardinfo **wcproot);
96 static void hmatch(struct info *infop, struct node *np, struct node *nextnp);
97 static void itree_pbubble(int flags, struct bubble *bp);
98 static void itree_destructor(void *left, void *right, void *arg);
99 static int itree_set_arrow_traits(struct arrow *ap, struct node *fromev,
100     struct node *toev, struct lut *ex);
101 static void itree_free_arrowlists(struct bubble *bubp, int arrows_too);
102 static void arrow_add_within(struct arrow *ap, struct node *xpr);
103 static struct arrow *itree_add_arrow(struct bubble *frombubblep,
104     struct bubble *tobubblep, struct node *apnode, struct node *fromevent,
105     struct node *toevent, struct lut *ex);
106 static struct constraintlist *itree_add_constraint(struct arrow *arrowp,
107     struct node *c);
108 static struct bubble *itree_add_bubble(struct event *eventp,
109     enum bubbletype btype, int nork, int gen);
110 static void itree_free_bubble(struct bubble *freeme);
111 static void itree_free_constraints(struct arrow *ap);
112 
113 /*
114  * the following struct contains the state we build up during
115  * vertical and horizontal expansion so that generate()
116  * has everything it needs to construct the appropriate arrows.
117  * after setting up the state by calling:
118  *	generate_arrownp()
119  *	generate_nork()
120  *	generate_new()
121  *	generate_from()
122  *	generate_to()
123  * the actual arrow generation is done by calling:
124  *	generate()
125  */
126 static struct {
127 	int generation;		/* generation number of arrow set */
128 	struct node *arrownp;	/* top-level parse tree for arrow */
129 	int n;			/* n value associated with arrow */
130 	int k;			/* k value associated with arrow */
131 	struct node *fromnp;	/* left-hand-side event in parse tree */
132 	struct node *tonp;	/* right-hand-side event in parse tree */
133 	struct event *frome;	/* left-hand-side event in instance tree */
134 	struct event *toe;	/* right-hand-side event in instance tree */
135 	struct bubble *frombp;	/* bubble arrow comes from */
136 	struct bubble *tobp;	/* bubble arrow goes to */
137 } G;
138 
139 static void
140 generate_arrownp(struct node *arrownp)
141 {
142 	G.arrownp = arrownp;
143 }
144 
145 static void
146 generate_nork(int n, int k)
147 {
148 	G.n = n;
149 	G.k = k;
150 }
151 
152 static void
153 generate_new(void)
154 {
155 	G.generation++;
156 }
157 
158 static void
159 generate_from(struct node *fromeventnp, struct event *fromevent)
160 {
161 	G.fromnp = fromeventnp;
162 	G.frome = fromevent;
163 
164 	out(O_ALTFP|O_VERB3|O_NONL, "from bubble on ");
165 	ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.fromnp);
166 	out(O_ALTFP|O_VERB3, NULL);
167 
168 	G.frombp = itree_add_bubble(G.frome, B_FROM, G.n, 0);
169 }
170 
171 static void
172 generate_to(struct node *toeventnp, struct event *toevent)
173 {
174 	G.tonp = toeventnp;
175 	G.toe = toevent;
176 
177 	out(O_ALTFP|O_VERB3|O_NONL, "to bubble (gen %d) on ", G.generation);
178 	ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.tonp);
179 	out(O_ALTFP|O_VERB3, NULL);
180 
181 	G.tobp = itree_add_bubble(G.toe, B_TO, G.k, G.generation);
182 }
183 
184 static void
185 generate(struct lut *ex)
186 {
187 	ASSERT(G.arrownp != NULL);
188 	ASSERT(G.fromnp != NULL);
189 	ASSERT(G.frome != NULL);
190 	ASSERT(G.frombp != NULL);
191 	ASSERT(G.tonp != NULL);
192 	ASSERT(G.toe != NULL);
193 	ASSERT(G.tobp != NULL);
194 
195 	out(O_ALTFP|O_VERB3|O_NONL, "        Arrow \"");
196 	ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.fromnp);
197 	out(O_ALTFP|O_VERB3|O_NONL, "\" -> \"");
198 	ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.tonp);
199 
200 	if (itree_add_arrow(G.frombp, G.tobp, G.arrownp,
201 	    G.fromnp, G.tonp, ex) == NULL) {
202 		out(O_ALTFP|O_VERB3, "\" (prevented by constraints)");
203 	} else {
204 		out(O_ALTFP|O_VERB3, "\"");
205 	}
206 }
207 
208 enum childnode_action {
209 	CN_NONE,
210 	CN_INSTANTIZE,
211 	CN_DUP
212 };
213 
214 static struct node *
215 tname_dup(struct node *namep, enum childnode_action act)
216 {
217 	struct node *retp = NULL;
218 	const char *file;
219 	int line;
220 
221 	if (namep == NULL)
222 		return (NULL);
223 
224 	file = namep->file;
225 	line = namep->line;
226 
227 	for (; namep != NULL; namep = namep->u.name.next) {
228 		struct node *newnp = newnode(T_NAME, file, line);
229 
230 		newnp->u.name.t = namep->u.name.t;
231 		newnp->u.name.s = namep->u.name.s;
232 		newnp->u.name.last = newnp;
233 		newnp->u.name.it = namep->u.name.it;
234 		newnp->u.name.cp = namep->u.name.cp;
235 
236 		if (act == CN_DUP) {
237 			struct node *npc;
238 
239 			npc = namep->u.name.child;
240 			if (npc != NULL) {
241 				switch (npc->t) {
242 				case T_NUM:
243 					newnp->u.name.child =
244 						newnode(T_NUM, file, line);
245 					newnp->u.name.child->u.ull =
246 						npc->u.ull;
247 					break;
248 				case T_NAME:
249 					newnp->u.name.child =
250 						tree_name(npc->u.name.s,
251 							npc->u.name.it,
252 							file, line);
253 					break;
254 				default:
255 					out(O_DIE, "tname_dup: "
256 					    "invalid child type %s",
257 					    ptree_nodetype2str(npc->t));
258 				}
259 			}
260 		} else if (act == CN_INSTANTIZE) {
261 			newnp->u.name.child = newnode(T_NUM, file, line);
262 
263 			if (namep->u.name.child == NULL ||
264 			    namep->u.name.child->t != T_NUM) {
265 				int inum;
266 
267 				ASSERT(newnp->u.name.cp != NULL);
268 				config_getcompname(newnp->u.name.cp,
269 						    NULL, &inum);
270 				newnp->u.name.child->u.ull =
271 					(unsigned long long)inum;
272 			} else {
273 				newnp->u.name.child->u.ull =
274 					namep->u.name.child->u.ull;
275 			}
276 		}
277 
278 		if (retp == NULL) {
279 			retp = newnp;
280 		} else {
281 			retp->u.name.last->u.name.next = newnp;
282 			retp->u.name.last = newnp;
283 		}
284 	}
285 
286 	return (retp);
287 }
288 
289 struct prop_wlk_data {
290 	struct lut *props;
291 	struct node *epname;
292 };
293 
294 static struct lut *props2instance(struct node *, struct node *);
295 
296 /*
297  * let oldepname be a subset of epname.  return the subsection of epname
298  * that ends with oldepname.  make each component in the path explicitly
299  * instanced (i.e., with a T_NUM child).
300  */
301 static struct node *
302 tname_dup_to_epname(struct node *oldepname, struct node *epname)
303 {
304 	struct node *npref, *npend, *np1, *np2;
305 	struct node *ret = NULL;
306 	int foundmatch = 0;
307 
308 	if (epname == NULL)
309 		return (NULL);
310 
311 	/*
312 	 * search for the longest path in epname which contains
313 	 * oldnode->u.event.epname.  set npend to point to just past the
314 	 * end of this path.
315 	 */
316 	npend = NULL;
317 	for (npref = epname; npref; npref = npref->u.name.next) {
318 		if (npref->u.name.s == oldepname->u.name.s) {
319 			for (np1 = npref, np2 = oldepname;
320 			    np1 != NULL && np2 != NULL;
321 			    np1 = np1->u.name.next, np2 = np2->u.name.next) {
322 				if (np1->u.name.s != np2->u.name.s)
323 					break;
324 			}
325 			if (np2 == NULL) {
326 				foundmatch = 1;
327 				npend = np1;
328 				if (np1 == NULL) {
329 					/* oldepname matched npref up to end */
330 					break;
331 				}
332 			}
333 		}
334 	}
335 
336 	if (foundmatch == 0) {
337 		/*
338 		 * if oldepname could not be found in epname, return a
339 		 * duplicate of the former.  do not try to instantize
340 		 * oldepname since it might not be a path.
341 		 */
342 		return (tname_dup(oldepname, CN_DUP));
343 	}
344 
345 	/*
346 	 * dup (epname -- npend).  all children should be T_NUMs.
347 	 */
348 	for (npref = epname;
349 	    ! (npref == NULL || npref == npend);
350 	    npref = npref->u.name.next) {
351 		struct node *newnp = newnode(T_NAME, oldepname->file,
352 					    oldepname->line);
353 
354 		newnp->u.name.t = npref->u.name.t;
355 		newnp->u.name.s = npref->u.name.s;
356 		newnp->u.name.last = newnp;
357 		newnp->u.name.it = npref->u.name.it;
358 		newnp->u.name.cp = npref->u.name.cp;
359 
360 		newnp->u.name.child = newnode(T_NUM, oldepname->file,
361 					    oldepname->line);
362 
363 		if (npref->u.name.child == NULL ||
364 		    npref->u.name.child->t != T_NUM) {
365 			int childnum;
366 
367 			ASSERT(npref->u.name.cp != NULL);
368 			config_getcompname(npref->u.name.cp, NULL, &childnum);
369 			newnp->u.name.child->u.ull = childnum;
370 		} else {
371 			newnp->u.name.child->u.ull =
372 				npref->u.name.child->u.ull;
373 		}
374 
375 		if (ret == NULL) {
376 			ret = newnp;
377 		} else {
378 			ret->u.name.last->u.name.next = newnp;
379 			ret->u.name.last = newnp;
380 		}
381 	}
382 
383 	return (ret);
384 }
385 
386 /*
387  * restriction: oldnode->u.event.epname has to be equivalent to or a subset
388  * of epname
389  */
390 static struct node *
391 tevent_dup_to_epname(struct node *oldnode, struct node *epname)
392 {
393 	struct node *ret;
394 
395 	ret = newnode(T_EVENT, oldnode->file, oldnode->line);
396 	ret->u.event.ename = tname_dup(oldnode->u.event.ename, CN_NONE);
397 	ret->u.event.epname = tname_dup_to_epname(oldnode->u.event.epname,
398 						    epname);
399 	return (ret);
400 }
401 
402 static void
403 nv_instantiate(void *name, void *val, void *arg)
404 {
405 	struct prop_wlk_data *pd = (struct prop_wlk_data *)arg;
406 	struct node *orhs = (struct node *)val;
407 	struct node *nrhs;
408 
409 	/* handle engines by instantizing the entire engine */
410 	if (name == L_engine) {
411 		ASSERT(orhs->t == T_EVENT);
412 		ASSERT(orhs->u.event.ename->u.name.t == N_SERD);
413 
414 		/* there are only SERD engines for now */
415 
416 		nrhs = newnode(T_SERD, orhs->file, orhs->line);
417 		nrhs->u.stmt.np = tevent_dup_to_epname(orhs, pd->epname);
418 		nrhs->u.stmt.lutp = props2instance(orhs, pd->epname);
419 		pd->props = lut_add(pd->props, name, nrhs, NULL);
420 		return;
421 	}
422 
423 	switch (orhs->t) {
424 	case T_NUM:
425 		nrhs = newnode(T_NUM, orhs->file, orhs->line);
426 		nrhs->u.ull = orhs->u.ull;
427 		pd->props = lut_add(pd->props, name, nrhs, NULL);
428 		break;
429 	case T_TIMEVAL:
430 		nrhs = newnode(T_TIMEVAL, orhs->file, orhs->line);
431 		nrhs->u.ull = orhs->u.ull;
432 		pd->props = lut_add(pd->props, name, nrhs, NULL);
433 		break;
434 	case T_NAME:
435 		nrhs = tname_dup_to_epname(orhs, pd->epname);
436 		pd->props = lut_add(pd->props, name, nrhs, NULL);
437 		break;
438 	case T_EVENT:
439 		nrhs = tevent_dup_to_epname(orhs, pd->epname);
440 		pd->props = lut_add(pd->props, name, nrhs, NULL);
441 		break;
442 	default:
443 		out(O_DEBUG, "unexpected nvpair value type %s",
444 		    ptree_nodetype2str(((struct node *)val)->t));
445 	}
446 }
447 
448 static struct lut *
449 props2instance(struct node *eventnp, struct node *epname)
450 {
451 	struct prop_wlk_data pd;
452 
453 	pd.props = NULL;
454 	pd.epname = epname;
455 
456 	ASSERT(eventnp->u.event.declp != NULL);
457 	lut_walk(eventnp->u.event.declp->u.stmt.lutp, nv_instantiate, &pd);
458 	return (pd.props);
459 }
460 
461 /*ARGSUSED*/
462 static void
463 instances_destructor(void *left, void *right, void *arg)
464 {
465 	struct node *dn = (struct node *)right;
466 
467 	if (dn->t == T_SERD) {
468 		/* we allocated the lut during itree_create(), so free it */
469 		lut_free(dn->u.stmt.lutp, instances_destructor, NULL);
470 		dn->u.stmt.lutp = NULL;
471 	}
472 	tree_free(dn);
473 }
474 
475 /*
476  * event_cmp -- used via lut_lookup/lut_add on instance tree lut
477  */
478 static int
479 event_cmp(struct event *ep1, struct event *ep2)
480 {
481 	int diff;
482 
483 	if ((diff = ep2->enode->u.event.ename->u.name.s -
484 	    ep1->enode->u.event.ename->u.name.s) != 0)
485 		return (diff);
486 	if ((diff = (char *)ep2->ipp - (char *)ep1->ipp) != 0)
487 		return (diff);
488 	return (0);
489 
490 }
491 
492 struct event *
493 itree_lookup(struct lut *itp, const char *ename, const struct ipath *ipp)
494 {
495 	struct event searchevent;	/* just used for searching */
496 	struct node searcheventnode;
497 	struct node searchenamenode;
498 
499 	searchevent.enode = &searcheventnode;
500 	searcheventnode.t = T_EVENT;
501 	searcheventnode.u.event.ename = &searchenamenode;
502 	searchenamenode.t = T_NAME;
503 	searchenamenode.u.name.s = ename;
504 	searchevent.ipp = ipp;
505 	return (lut_lookup(itp, (void *)&searchevent, (lut_cmp)event_cmp));
506 }
507 
508 static struct event *
509 find_or_add_event(struct info *infop, struct node *np)
510 {
511 	struct event *ret;
512 	struct event searchevent;	/* just used for searching */
513 
514 	ASSERTeq(np->t, T_EVENT, ptree_nodetype2str);
515 
516 	searchevent.enode = np;
517 	searchevent.ipp = ipath(np->u.event.epname);
518 	if ((ret = lut_lookup(infop->lut, (void *)&searchevent,
519 	    (lut_cmp)event_cmp)) != NULL)
520 		return (ret);
521 
522 	/* wasn't already in tree, allocate it */
523 	ret = MALLOC(sizeof (*ret));
524 	bzero(ret, sizeof (*ret));
525 
526 	ret->t = np->u.event.ename->u.name.t;
527 	ret->enode = np;
528 	ret->ipp = searchevent.ipp;
529 	ret->props = props2instance(np, np->u.event.epname);
530 
531 	infop->lut = lut_add(infop->lut, (void *)ret, (void *)ret,
532 	    (lut_cmp)event_cmp);
533 
534 	return (ret);
535 }
536 
537 /*
538  * hmatch_event -- perform any appropriate horizontal expansion on an event
539  *
540  * this routine is used to perform horizontal expansion on both the
541  * left-hand-side events in a prop, and the right-hand-side events.
542  * when called to handle a left-side event, nextnp point to the right
543  * side of the prop that should be passed to hmatch() for each match
544  * found by horizontal expansion.   when no horizontal expansion exists,
545  * we will still "match" one event for every event found in the list on
546  * the left-hand-side of the prop because vmatch() already found that
547  * there's at least one match during vertical expansion.
548  */
549 static void
550 hmatch_event(struct info *infop, struct node *eventnp, struct node *epname,
551     struct config *ncp, struct node *nextnp, int rematch)
552 {
553 	if (epname == NULL) {
554 		/*
555 		 * end of pathname recursion, either we just located
556 		 * a left-hand-side event and we're ready to move on
557 		 * to the expanding the right-hand-side events, or
558 		 * we're further down the recursion and we just located
559 		 * a right-hand-side event.  the passed-in parameter
560 		 * "nextnp" tells us whether we're working on the left
561 		 * side and need to move on to nextnp, or if nextnp is
562 		 * NULL, we're working on the right side.
563 		 */
564 		if (nextnp) {
565 			/*
566 			 * finished a left side expansion, move on to right.
567 			 * tell generate() what event we just matched so
568 			 * it can be used at the source of any arrows
569 			 * we generate as we match events on the right side.
570 			 */
571 			generate_from(eventnp,
572 			    find_or_add_event(infop, eventnp));
573 			hmatch(infop, nextnp, NULL);
574 		} else {
575 			/*
576 			 * finished a right side expansion.  tell generate
577 			 * the information about the destination and let
578 			 * it construct the arrows as appropriate.
579 			 */
580 			generate_to(eventnp,
581 			    find_or_add_event(infop, eventnp));
582 			generate(infop->ex);
583 		}
584 
585 		return;
586 	}
587 
588 	ASSERTeq(epname->t, T_NAME, ptree_nodetype2str);
589 
590 	/*
591 	 * we only get here when eventnp already has a completely
592 	 * instanced epname in it already.  so we first recurse
593 	 * down to the end of the name and as the recursion pops
594 	 * up, we look for opportunities to advance horizontal
595 	 * expansions on to the next match.  when we do advance
596 	 * horizontal expansions, we potentially render all cp
597 	 * pointers on all components to the right as invalid,
598 	 * so we pass in an "ncp" config handle so matching against
599 	 * the config can happen.
600 	 */
601 	if (rematch) {
602 		struct config *ocp = epname->u.name.cp;
603 		char *ncp_s;
604 		int ncp_num, num;
605 
606 		for (; ncp; ncp = config_next(ncp)) {
607 			config_getcompname(ncp, &ncp_s, &ncp_num);
608 
609 			if (ncp_s == epname->u.name.s) {
610 				/* found a matching component name */
611 				config_getcompname(epname->u.name.cp,
612 				    NULL, &num);
613 
614 				if (epname->u.name.it != IT_HORIZONTAL &&
615 				    ncp_num != num)
616 					continue;
617 
618 				epname->u.name.cp = ncp;
619 				hmatch_event(infop, eventnp,
620 				    epname->u.name.next, config_child(ncp),
621 				    nextnp, 1);
622 			}
623 		}
624 
625 		epname->u.name.cp = ocp;
626 
627 		return;		/* no more config to match against */
628 
629 	} else {
630 		hmatch_event(infop, eventnp, epname->u.name.next, ncp,
631 		    nextnp, 0);
632 	}
633 
634 	if (epname->u.name.it == IT_HORIZONTAL) {
635 		struct config *cp;
636 		struct config *ocp = epname->u.name.cp;
637 		char *cp_s;
638 		int cp_num;
639 		int ocp_num;
640 		struct iterinfo *iterinfop = NULL;
641 		const char *iters;
642 
643 		config_getcompname(ocp, NULL, &ocp_num);
644 
645 		for (cp = config_next(ocp); cp; cp = config_next(cp)) {
646 			config_getcompname(cp, &cp_s, &cp_num);
647 
648 			if (cp_s == epname->u.name.s) {
649 				ASSERT(epname->u.name.child != NULL);
650 
651 				iters = epname->u.name.child->u.name.s;
652 				if ((iterinfop = lut_lookup(infop->ex,
653 				    (void *)iters, NULL)) == NULL) {
654 					out(O_DIE,
655 					    "hmatch_event: internal error: "
656 					    "iterator \"%s\" undefined", iters);
657 				} else {
658 					/* advance dict entry to next match */
659 					iterinfop->num = cp_num;
660 				}
661 				epname->u.name.cp = cp;
662 				hmatch_event(infop, eventnp,
663 				    epname->u.name.next, config_child(cp),
664 				    nextnp, 1);
665 			}
666 		}
667 
668 		if (iterinfop != NULL) {
669 			/* restore dict entry */
670 			iterinfop->num = ocp_num;
671 		}
672 		epname->u.name.cp = ocp;
673 	}
674 }
675 
676 /*
677  * hmatch -- check for horizontal expansion matches
678  *
679  * np points to the things we're matching (like a T_LIST or a T_EVENT)
680  * and if we're working on a left-side of a prop, nextnp points to
681  * the other side of the prop that we'll tackle next when this recursion
682  * bottoms out.  when all the events in the entire prop arrow have been
683  * horizontally expanded, generate() will be called to generate the
684  * actualy arrow.
685  */
686 static void
687 hmatch(struct info *infop, struct node *np, struct node *nextnp)
688 {
689 	if (np == NULL)
690 		return;		/* all done */
691 
692 	/*
693 	 * for each item in the list of events (which could just
694 	 * be a single event, or it could get larger in the loop
695 	 * below due to horizontal expansion), call hmatch on
696 	 * the right side and create arrows to each element.
697 	 */
698 
699 	switch (np->t) {
700 	case T_LIST:
701 		/* loop through the list */
702 		if (np->u.expr.left)
703 			hmatch(infop, np->u.expr.left, nextnp);
704 		if (np->u.expr.right)
705 			hmatch(infop, np->u.expr.right, nextnp);
706 		break;
707 
708 	case T_EVENT:
709 		hmatch_event(infop, np, np->u.event.epname,
710 		    NULL, nextnp, 0);
711 		break;
712 
713 	default:
714 		outfl(O_DIE, np->file, np->line,
715 		    "hmatch: unexpected type: %s",
716 		    ptree_nodetype2str(np->t));
717 	}
718 }
719 
720 static int
721 itree_np2nork(struct node *norknp)
722 {
723 	if (norknp == NULL)
724 		return (1);
725 	else if (norknp->t == T_NAME && norknp->u.name.s == L_A)
726 		return (-1);	/* our internal version of "all" */
727 	else if (norknp->t == T_NUM)
728 		return ((int)norknp->u.ull);
729 	else
730 		out(O_DIE, norknp->file, norknp->line,
731 		    "itree_np2nork: internal error type %s",
732 		    ptree_nodetype2str(norknp->t));
733 	/*NOTREACHED*/
734 }
735 
736 static struct iterinfo *
737 newiterinfo(int num, struct node *np)
738 {
739 	struct iterinfo *ret = MALLOC(sizeof (*ret));
740 
741 	ret->num = num;
742 	ret->np = np;
743 
744 	return (ret);
745 }
746 
747 /*ARGSUSED*/
748 static void
749 iterinfo_destructor(void *left, void *right, void *arg)
750 {
751 	struct iterinfo *iterinfop = (struct iterinfo *)right;
752 
753 	bzero(iterinfop, sizeof (*iterinfop));
754 	FREE(iterinfop);
755 }
756 
757 /*
758  * update epname to include the wildcarded portion
759  */
760 static void
761 create_wildcardedpath(struct wildcardinfo **wcproot)
762 {
763 	struct wildcardinfo *wcp;
764 	struct node *nptop;
765 
766 	wcp = *wcproot;
767 
768 	if (wcp->s == WC_UNDERCONSTRUCTION) {
769 		ASSERT(wcp->p->refcount == 1);
770 		wcp->s = WC_COMPLETE;
771 	}
772 
773 	/* path has no wildcard */
774 	if (wcp->p->ewname == NULL)
775 		return;
776 
777 	/*
778 	 * get to this point if a wildcard portion of the path exists.
779 	 *
780 	 * first set oldepname to the start of the existing epname for use
781 	 * in future comparisons, then update epname to include the
782 	 * wildcard portion.
783 	 */
784 	nptop = wcp->nptop;
785 
786 	ASSERT(wcp->oldepname == nptop->u.event.epname);
787 
788 	nptop->u.event.epname =	tname_dup(wcp->p->ewname, CN_DUP);
789 	nptop->u.event.epname = tree_name_append(nptop->u.event.epname,
790 					tname_dup(wcp->oldepname, CN_DUP));
791 }
792 
793 /*
794  * restore epname to its former (nonwildcarded) state
795  */
796 static void
797 undo_wildcardedpath(struct wildcardinfo **wcproot)
798 {
799 	struct wildcardinfo *wcp;
800 
801 	wcp = *wcproot;
802 
803 	if (wcp->s == WC_COMPLETE) {
804 		ASSERT(wcp->p->refcount == 1);
805 		wcp->s = WC_UNDERCONSTRUCTION;
806 	}
807 
808 	/* path has no wildcard */
809 	if (wcp->p->ewname == NULL)
810 		return;
811 
812 	ASSERT(wcp->oldepname != NULL);
813 
814 	tree_free(wcp->nptop->u.event.epname);
815 	wcp->nptop->u.event.epname = wcp->oldepname;
816 }
817 
818 static void
819 vmatch_event(struct info *infop, struct config *cp, struct node *np,
820 	    struct node *lnp, struct node *anp,
821 	    struct wildcardinfo **wcproot, int dowildcard)
822 {
823 	struct wildcardinfo *wcp;
824 	char *cp_s;
825 	int cp_num;
826 
827 	wcp = *wcproot;
828 
829 	if ((np == NULL && wcp->oldepname != NULL) ||
830 	    (cp == NULL && wcp->oldepname == NULL)) {
831 		/*
832 		 * the pathname matched the config (but not necessarily a
833 		 * match at the end)
834 		 */
835 		create_wildcardedpath(wcproot);
836 		vmatch(infop, np, lnp, anp, wcproot);
837 		undo_wildcardedpath(wcproot);
838 
839 		if (cp != NULL && wcp->s == WC_UNDERCONSTRUCTION) {
840 			/*
841 			 * pathname match did not occur at the end of the
842 			 * configuration path.  more matches may be found
843 			 * later in the path, so we set cpforcedwc to force
844 			 * wildcarding for startcp.
845 			 *
846 			 * note that cpforcedwc may already have been set
847 			 * in an earlier match due to vertical expansion on
848 			 * the nonwildcarded epname.
849 			 */
850 			if (wcp->p->cpforcedwc != wcp->p->cpstart) {
851 				ASSERT(wcp->p->cpforcedwc == NULL);
852 				wcp->p->cpforcedwc = wcp->p->cpstart;
853 			}
854 		}
855 
856 		return;
857 	}
858 
859 	if (cp == NULL)
860 		return;	/* no more config to match against */
861 
862 	for (; cp; cp = config_next(cp)) {
863 		config_getcompname(cp, &cp_s, &cp_num);
864 
865 		if (cp_s == np->u.name.s &&
866 		    ! (wcp->s == WC_UNDERCONSTRUCTION &&
867 		    cp == wcp->p->cpstart &&
868 		    wcp->p->cpstart == wcp->p->cpforcedwc)) {
869 			/* found a matching component name */
870 			if (np->u.name.child &&
871 			    np->u.name.child->t == T_NUM) {
872 				/*
873 				 * an explicit instance number was given
874 				 * in the source.  so only consider this
875 				 * a configuration match if the number
876 				 * also matches.
877 				 */
878 				if (cp_num != np->u.name.child->u.ull)
879 					continue;
880 
881 				np->u.name.cp = cp;
882 			} else {
883 				struct iterinfo *iterinfop;
884 				const char *iters;
885 
886 				/*
887 				 * vertical iterator.  look it up in
888 				 * the appropriate lut and if we get
889 				 * back a value it is either one that we
890 				 * set earlier, in which case we record
891 				 * the new value for this iteration and
892 				 * keep matching, or it is one that was
893 				 * set by an earlier reference to the
894 				 * iterator, in which case we only consider
895 				 * this a configuration match if the number
896 				 * matches cp_num.
897 				 */
898 
899 				ASSERT(np->u.name.child != NULL);
900 				ASSERT(np->u.name.child->t == T_NAME);
901 				iters = np->u.name.child->u.name.s;
902 
903 				if ((iterinfop = lut_lookup(infop->ex,
904 				    (void *)iters, NULL)) == NULL) {
905 					/* we're the first use, record our np */
906 					infop->ex = lut_add(infop->ex,
907 					    (void *)iters,
908 					    newiterinfo(cp_num, np), NULL);
909 				} else if (np == iterinfop->np) {
910 					/*
911 					 * we're the first use, back again
912 					 * for another iteration.  so update
913 					 * the num bound to this iterator in
914 					 * the lut.
915 					 */
916 					iterinfop->num = cp_num;
917 				} else if (cp_num != iterinfop->num) {
918 					/*
919 					 * an earlier reference to this
920 					 * iterator bound it to a different
921 					 * instance number, so there's no
922 					 * match here after all.
923 					 */
924 					continue;
925 				}
926 				np->u.name.cp = cp;
927 			}
928 
929 			/*
930 			 * if wildcarding was done in a call earlier in the
931 			 * stack, record the current cp as the first
932 			 * matching and nonwildcarded cp.
933 			 */
934 			if (dowildcard && wcp->s == WC_UNDERCONSTRUCTION)
935 				wcp->p->cpstart = cp;
936 
937 			/*
938 			 * if this was an IT_HORIZONTAL name,
939 			 * hmatch() will use the cp to expand
940 			 * all matches horizontally into a list.
941 			 * we know the list will contain at least
942 			 * one element (the one we just matched),
943 			 * so we just store cp and let hmatch_event()
944 			 * do the rest.
945 			 *
946 			 * recurse on to next component.  note that
947 			 * wildcarding is now turned off.
948 			 */
949 			vmatch_event(infop, config_child(cp), np->u.name.next,
950 				    lnp, anp, wcproot, 0);
951 
952 			/*
953 			 * if wildcarding is being forced for this
954 			 * component, repeat call to vmatch_event() with
955 			 * the same np
956 			 */
957 			if (dowildcard &&
958 			    wcp->s == WC_UNDERCONSTRUCTION &&
959 			    cp == wcp->p->cpforcedwc) {
960 				vmatch_event(infop, cp, np, lnp, anp,
961 					    wcproot, 1);
962 			}
963 
964 			if (np->u.name.it == IT_HORIZONTAL) {
965 				/*
966 				 * hmatch() finished iterating through
967 				 * the configuration as described above, so
968 				 * don't continue iterating here.
969 				 */
970 				return;
971 			}
972 
973 		} else if (dowildcard && wcp->s == WC_UNDERCONSTRUCTION) {
974 			/*
975 			 * no matching cp, and we are constructing our own
976 			 * wildcard path.  (in other words, we are not
977 			 * referencing a wildcard path created for an
978 			 * earlier event.)
979 			 *
980 			 * add wildcard entry, then recurse on to config
981 			 * child
982 			 */
983 			struct node *cpnode, *prevlast;
984 
985 			if (wcp->p->cpstart == wcp->p->cpforcedwc)
986 				wcp->p->cpforcedwc = NULL;
987 
988 			cpnode = tree_name(cp_s, IT_NONE, NULL, 0);
989 			cpnode->u.name.child = newnode(T_NUM, NULL, 0);
990 			cpnode->u.name.child->u.ull = cp_num;
991 			cpnode->u.name.cp = cp;
992 
993 			if (wcp->p->ewname == NULL) {
994 				prevlast = NULL;
995 				wcp->p->ewname = cpnode;
996 			} else {
997 				prevlast = wcp->p->ewname->u.name.last;
998 				wcp->p->ewname =
999 					tree_name_append(wcp->p->ewname,
1000 							    cpnode);
1001 			}
1002 
1003 			vmatch_event(infop, config_child(cp), np, lnp, anp,
1004 				    wcproot, 1);
1005 
1006 			/*
1007 			 * back out last addition to ewname and continue
1008 			 * with loop
1009 			 */
1010 			tree_free(cpnode);
1011 			if (prevlast == NULL) {
1012 				wcp->p->ewname = NULL;
1013 			} else {
1014 				prevlast->u.name.next = NULL;
1015 				wcp->p->ewname->u.name.last = prevlast;
1016 			}
1017 		}
1018 	}
1019 }
1020 
1021 /*
1022  * for the event node np, which will be subjected to pathname
1023  * expansion/matching, create a (struct wildcardinfo) to hold wildcard
1024  * information.  this struct will be inserted into the first location in
1025  * the list that starts with *wcproot.
1026  *
1027  * cp is the starting node of the configuration; cpstart, which is output,
1028  * is the starting node of the nonwildcarded portion of the path.
1029  */
1030 static void
1031 add_wildcardentry(struct wildcardinfo **wcproot, struct config *cp,
1032 		struct node *np, struct config **cpstart)
1033 {
1034 	struct wildcardinfo *wcpnew, *wcp;
1035 	struct node *np1, *np2;
1036 
1037 	/*
1038 	 * create entry for np
1039 	 */
1040 	wcpnew = MALLOC(sizeof (struct wildcardinfo));
1041 	bzero(wcpnew, sizeof (struct wildcardinfo));
1042 	wcpnew->nptop = np;
1043 	wcpnew->oldepname = np->u.event.epname;
1044 	np2 = wcpnew->oldepname;
1045 
1046 	/*
1047 	 * search all completed entries for an epname whose first entry
1048 	 * matches.  note that NULL epnames are considered valid and can be
1049 	 * matched.
1050 	 */
1051 	for (wcp = *wcproot; wcp; wcp = wcp->next) {
1052 		ASSERT(wcp->s == WC_COMPLETE || wcp->s == WC_REFERENCING);
1053 		if (wcp->s != WC_COMPLETE)
1054 			continue;
1055 
1056 		np1 = wcp->oldepname;
1057 		if ((np1 && np2 && np1->u.name.s == np2->u.name.s) ||
1058 		    (np1 == NULL && np2 == NULL)) {
1059 			wcpnew->p = wcp->p;
1060 			wcpnew->s = WC_REFERENCING;
1061 
1062 			wcp->p->refcount++;
1063 			break;
1064 		}
1065 	}
1066 
1067 	if (wcpnew->p == NULL) {
1068 		wcpnew->s = WC_UNDERCONSTRUCTION;
1069 
1070 		wcpnew->p = MALLOC(sizeof (struct wildcardpath));
1071 		bzero(wcpnew->p, sizeof (struct wildcardpath));
1072 		wcpnew->p->cpstart = cp;
1073 		wcpnew->p->refcount = 1;
1074 	}
1075 
1076 	wcpnew->next = *wcproot;
1077 	*wcproot = wcpnew;
1078 
1079 	*cpstart = wcpnew->p->cpstart;
1080 }
1081 
1082 static void
1083 delete_wildcardentry(struct wildcardinfo **wcproot)
1084 {
1085 	struct wildcardinfo *wcp;
1086 
1087 	wcp = *wcproot;
1088 	*wcproot = wcp->next;
1089 
1090 	switch (wcp->s) {
1091 	case WC_UNDERCONSTRUCTION:
1092 	case WC_COMPLETE:
1093 		ASSERT(wcp->p->refcount == 1);
1094 		tree_free(wcp->p->ewname);
1095 		FREE(wcp->p);
1096 		break;
1097 
1098 	case WC_REFERENCING:
1099 		ASSERT(wcp->p->refcount > 1);
1100 		wcp->p->refcount--;
1101 		break;
1102 
1103 	default:
1104 		out(O_DIE, "deletewc: invalid status");
1105 		break;
1106 	}
1107 
1108 	FREE(wcp);
1109 }
1110 
1111 /*
1112  * vmatch -- find the next vertical expansion match in the config database
1113  *
1114  * this routine is called with three node pointers:
1115  *	 np -- the parse we're matching
1116  *	lnp -- the rest of the list we're currently working on
1117  *	anp -- the rest of the arrow we're currently working on
1118  *
1119  * the expansion matching happens via three types of recursion:
1120  *
1121  *	- when given an arrow, handle the left-side and then recursively
1122  *	  handle the right side (which might be another cascaded arrow).
1123  *
1124  *	- when handling one side of an arrow, recurse through the T_LIST
1125  *	  to get to each event (or just move on to the event if there
1126  *	  is a single event instead of a list)  since the arrow parse
1127  *	  trees recurse left, we actually start with the right-most
1128  *	  event list in the prop statement and work our way towards
1129  *	  the left-most event list.
1130  *
1131  *	- when handling an event, recurse down each component of the
1132  *	  pathname, matching in the config database and recording the
1133  *	  matches in the explicit iterator dictionary as we go.
1134  *
1135  * when the bottom of this matching recursion is met, meaning we have
1136  * set the "cp" pointers on all the names in the entire statement,
1137  * we call hmatch() which does it's own recursion to handle horizontal
1138  * expandsion and then call generate() to generate nodes, bubbles, and
1139  * arrows in the instance tree.  generate() looks at the cp pointers to
1140  * see what instance numbers were matched in the configuration database.
1141  *
1142  * when horizontal expansion appears, vmatch() finds only the first match
1143  * and hmatch() then takes the horizontal expansion through all the other
1144  * matches when generating the arrows in the instance tree.
1145  *
1146  * the "infop" passed down through the recursion contains a dictionary
1147  * of the explicit iterators (all the implicit iterators have been converted
1148  * to explicit iterators when the parse tree was created by tree.c), which
1149  * allows things like this to work correctly:
1150  *
1151  *	prop error.a@x[n]/y/z -> error.b@x/y[n]/z -> error.c@x/y/z[n];
1152  *
1153  * during the top level call, the explicit iterator "n" will match an
1154  * instance number in the config database, and the result will be recorded
1155  * in the explicit iterator dictionary and passed down via "infop".  so
1156  * when the recursive call tries to match y[n] in the config database, it
1157  * will only match the same instance number as x[n] did since the dictionary
1158  * is consulted to see if "n" took on a value already.
1159  *
1160  * at any point during the recursion, match*() can return to indicate
1161  * a match was not found in the config database and that the caller should
1162  * move on to the next potential match, if any.
1163  *
1164  * constraints are completely ignored by match(), so the statement:
1165  *
1166  *	prop error.a@x[n] -> error.b@x[n] {n != 0};
1167  *
1168  * might very well match x[0] if it appears in the config database.  it
1169  * is the generate() routine that takes that match and then decides what
1170  * arrow, if any, should be generated in the instance tree.  generate()
1171  * looks at the explicit iterator dictionary to get values like "n" in
1172  * the above example so that it can evaluate constraints.
1173  *
1174  */
1175 static void
1176 vmatch(struct info *infop, struct node *np, struct node *lnp,
1177     struct node *anp, struct wildcardinfo **wcproot)
1178 {
1179 	if (np == NULL) {
1180 		if (lnp)
1181 			vmatch(infop, lnp, NULL, anp, wcproot);
1182 		else if (anp)
1183 			vmatch(infop, anp, NULL, NULL, wcproot);
1184 		else {
1185 			struct node *src;
1186 			struct node *dst;
1187 
1188 			/* end of vertical match recursion */
1189 			outfl(O_ALTFP|O_VERB3|O_NONL,
1190 			    infop->anp->file, infop->anp->line, "vmatch: ");
1191 			ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, infop->anp);
1192 			out(O_ALTFP|O_VERB3, NULL);
1193 
1194 			generate_nork(
1195 			    itree_np2nork(infop->anp->u.arrow.nnp),
1196 			    itree_np2nork(infop->anp->u.arrow.knp));
1197 			dst = infop->anp->u.arrow.rhs;
1198 			src = infop->anp->u.arrow.lhs;
1199 			for (;;) {
1200 				generate_new();	/* new set of arrows */
1201 				if (src->t == T_ARROW) {
1202 					hmatch(infop, src->u.arrow.rhs, dst);
1203 					generate_nork(
1204 					    itree_np2nork(src->u.arrow.nnp),
1205 					    itree_np2nork(src->u.arrow.knp));
1206 					dst = src->u.arrow.rhs;
1207 					src = src->u.arrow.lhs;
1208 				} else {
1209 					hmatch(infop, src, dst);
1210 					break;
1211 				}
1212 			}
1213 		}
1214 		return;
1215 	}
1216 
1217 	switch (np->t) {
1218 	case T_EVENT: {
1219 		struct config *cpstart;
1220 
1221 		add_wildcardentry(wcproot, config_child(infop->croot),
1222 				np, &cpstart);
1223 		vmatch_event(infop, cpstart, np->u.event.epname, lnp, anp,
1224 			    wcproot, 1);
1225 		delete_wildcardentry(wcproot);
1226 		break;
1227 	}
1228 	case T_LIST:
1229 		ASSERT(lnp == NULL);
1230 		vmatch(infop, np->u.expr.right, np->u.expr.left, anp, wcproot);
1231 		break;
1232 
1233 	case T_ARROW:
1234 		ASSERT(lnp == NULL && anp == NULL);
1235 		vmatch(infop, np->u.arrow.rhs, NULL, np->u.arrow.lhs, wcproot);
1236 		break;
1237 
1238 	default:
1239 		outfl(O_DIE, np->file, np->line,
1240 		    "vmatch: unexpected type: %s",
1241 		    ptree_nodetype2str(np->t));
1242 	}
1243 }
1244 
1245 static void
1246 cp_reset(struct node *np)
1247 {
1248 	if (np == NULL)
1249 		return;
1250 	switch (np->t) {
1251 	case T_NAME:
1252 		np->u.name.cp = NULL;
1253 		cp_reset(np->u.name.next);
1254 		break;
1255 
1256 	case T_LIST:
1257 		cp_reset(np->u.expr.left);
1258 		cp_reset(np->u.expr.right);
1259 		break;
1260 
1261 	case T_ARROW:
1262 		cp_reset(np->u.arrow.lhs);
1263 		cp_reset(np->u.arrow.rhs);
1264 		break;
1265 
1266 	case T_EVENT:
1267 		cp_reset(np->u.event.epname);
1268 		break;
1269 	}
1270 }
1271 
1272 /*
1273  * itree_create -- apply the current config to the current parse tree
1274  *
1275  * returns a lut mapping fully-instance-qualified names to struct events.
1276  *
1277  */
1278 struct lut *
1279 itree_create(struct config *croot)
1280 {
1281 	struct lut *retval;
1282 	struct node *propnp;
1283 
1284 	Ninfo.lut = NULL;
1285 	Ninfo.croot = croot;
1286 	for (propnp = Props; propnp; propnp = propnp->u.stmt.next) {
1287 		struct node *anp = propnp->u.stmt.np;
1288 		struct wildcardinfo *wcproot = NULL;
1289 
1290 		ASSERTeq(anp->t, T_ARROW, ptree_nodetype2str);
1291 
1292 		Ninfo.anp = anp;
1293 		Ninfo.ex = NULL;
1294 
1295 		generate_arrownp(anp);
1296 		vmatch(&Ninfo, anp, NULL, NULL, &wcproot);
1297 
1298 		if (Ninfo.ex) {
1299 			lut_free(Ninfo.ex, iterinfo_destructor, NULL);
1300 			Ninfo.ex = NULL;
1301 		}
1302 		ASSERT(wcproot == NULL);
1303 		cp_reset(anp);
1304 	}
1305 
1306 	retval = Ninfo.lut;
1307 	Ninfo.lut = NULL;
1308 	return (retval);
1309 }
1310 
1311 void
1312 itree_free(struct lut *lutp)
1313 {
1314 	lut_free(lutp, itree_destructor, NULL);
1315 }
1316 
1317 int
1318 itree_nameinstancecmp(struct node *np1, struct node *np2)
1319 {
1320 	int np1type = (int)np1->u.name.t;
1321 	int np2type = (int)np2->u.name.t;
1322 	int num1;
1323 	int num2;
1324 
1325 	while (np1 && np2 && np1->u.name.s == np2->u.name.s) {
1326 		if (np1->u.name.next != NULL && np2->u.name.next != NULL) {
1327 			if (np1->u.name.cp != NULL) {
1328 				config_getcompname(np1->u.name.cp, NULL, &num1);
1329 			} else {
1330 				ASSERT(np1->u.name.child != NULL);
1331 				ASSERT(np1->u.name.child->t == T_NUM);
1332 				num1 = (int)np1->u.name.child->u.ull;
1333 			}
1334 
1335 			if (np2->u.name.cp != NULL) {
1336 				config_getcompname(np2->u.name.cp, NULL, &num2);
1337 			} else {
1338 				ASSERT(np2->u.name.child != NULL);
1339 				ASSERT(np2->u.name.child->t == T_NUM);
1340 				num2 = (int)np2->u.name.child->u.ull;
1341 			}
1342 
1343 			if (num1 != num2)
1344 				return (num1 - num2);
1345 		}
1346 
1347 		np1 = np1->u.name.next;
1348 		np2 = np2->u.name.next;
1349 	}
1350 	if (np1 == NULL)
1351 		if (np2 == NULL)
1352 			return (np1type - np2type);
1353 		else
1354 			return (-1);
1355 	else if (np2 == NULL)
1356 		return (1);
1357 	else
1358 		return (strcmp(np1->u.name.s, np2->u.name.s));
1359 }
1360 
1361 void
1362 itree_pevent_brief(int flags, struct event *ep)
1363 {
1364 	ASSERT(ep != NULL);
1365 	ASSERT(ep->enode != NULL);
1366 	ASSERT(ep->ipp != NULL);
1367 
1368 	ipath_print(flags, ep->enode->u.event.ename->u.name.s, ep->ipp);
1369 }
1370 
1371 /*ARGSUSED*/
1372 static void
1373 itree_pevent(struct event *lhs, struct event *ep, void *arg)
1374 {
1375 	struct plut_wlk_data propd;
1376 	struct bubble *bp;
1377 	int flags = (int)arg;
1378 
1379 	itree_pevent_brief(flags, ep);
1380 	if (ep->t == N_EREPORT)
1381 		out(flags, " (count %d)", ep->count);
1382 	else
1383 		out(flags, NULL);
1384 
1385 	if (ep->props) {
1386 		propd.flags = flags;
1387 		propd.first = 1;
1388 		out(flags, "Properties:");
1389 		lut_walk(ep->props, ptree_plut, (void *)&propd);
1390 	}
1391 
1392 	for (bp = itree_next_bubble(ep, NULL); bp;
1393 	    bp = itree_next_bubble(ep, bp)) {
1394 		/* Print only TO bubbles in this loop */
1395 		if (bp->t != B_TO)
1396 			continue;
1397 		itree_pbubble(flags, bp);
1398 	}
1399 
1400 	for (bp = itree_next_bubble(ep, NULL); bp;
1401 	    bp = itree_next_bubble(ep, bp)) {
1402 		/* Print only INHIBIT bubbles in this loop */
1403 		if (bp->t != B_INHIBIT)
1404 			continue;
1405 		itree_pbubble(flags, bp);
1406 	}
1407 
1408 	for (bp = itree_next_bubble(ep, NULL); bp;
1409 	    bp = itree_next_bubble(ep, bp)) {
1410 		/* Print only FROM bubbles in this loop */
1411 		if (bp->t != B_FROM)
1412 			continue;
1413 		itree_pbubble(flags, bp);
1414 	}
1415 }
1416 
1417 static void
1418 itree_pbubble(int flags, struct bubble *bp)
1419 {
1420 	struct constraintlist *cp;
1421 	struct arrowlist *ap;
1422 
1423 	ASSERT(bp != NULL);
1424 
1425 	out(flags|O_NONL, "   ");
1426 	if (bp->mark)
1427 		out(flags|O_NONL, "*");
1428 	else
1429 		out(flags|O_NONL, " ");
1430 	if (bp->t == B_FROM)
1431 		out(flags|O_NONL, "N=%d to:", bp->nork);
1432 	else if (bp->t == B_TO)
1433 		out(flags|O_NONL, "K=%d from:", bp->nork);
1434 	else
1435 		out(flags|O_NONL, "K=%d masked from:", bp->nork);
1436 
1437 	if (bp->t == B_TO || bp->t == B_INHIBIT) {
1438 		for (ap = itree_next_arrow(bp, NULL); ap;
1439 		    ap = itree_next_arrow(bp, ap)) {
1440 			ASSERT(ap->arrowp->head == bp);
1441 			ASSERT(ap->arrowp->tail != NULL);
1442 			ASSERT(ap->arrowp->tail->myevent != NULL);
1443 			out(flags|O_NONL, " ");
1444 			itree_pevent_brief(flags, ap->arrowp->tail->myevent);
1445 		}
1446 		out(flags, NULL);
1447 		return;
1448 	}
1449 
1450 	for (ap = itree_next_arrow(bp, NULL); ap;
1451 	    ap = itree_next_arrow(bp, ap)) {
1452 		ASSERT(ap->arrowp->tail == bp);
1453 		ASSERT(ap->arrowp->head != NULL);
1454 		ASSERT(ap->arrowp->head->myevent != NULL);
1455 
1456 		out(flags|O_NONL, " ");
1457 		itree_pevent_brief(flags, ap->arrowp->head->myevent);
1458 
1459 		out(flags|O_NONL, " ");
1460 		ptree_timeval(flags, &ap->arrowp->mindelay);
1461 		out(flags|O_NONL, ",");
1462 		ptree_timeval(flags, &ap->arrowp->maxdelay);
1463 
1464 		/* Display anything from the propogation node? */
1465 		out(O_VERB3|O_NONL, " <%s:%d>",
1466 		    ap->arrowp->pnode->file, ap->arrowp->pnode->line);
1467 
1468 		if (itree_next_constraint(ap->arrowp, NULL))
1469 			out(flags|O_NONL, " {");
1470 
1471 		for (cp = itree_next_constraint(ap->arrowp, NULL); cp;
1472 		    cp = itree_next_constraint(ap->arrowp, cp)) {
1473 			ptree(flags, cp->cnode, 1, 0);
1474 			if (itree_next_constraint(ap->arrowp, cp))
1475 				out(flags|O_NONL, ", ");
1476 		}
1477 
1478 		if (itree_next_constraint(ap->arrowp, NULL))
1479 			out(flags|O_NONL, "}");
1480 	}
1481 	out(flags, NULL);
1482 }
1483 
1484 void
1485 itree_ptree(int flags, struct lut *itp)
1486 {
1487 	lut_walk(itp, (lut_cb)itree_pevent, (void *)flags);
1488 }
1489 
1490 /*ARGSUSED*/
1491 static void
1492 itree_destructor(void *left, void *right, void *arg)
1493 {
1494 	struct event *ep = (struct event *)right;
1495 	struct bubble *nextbub, *bub;
1496 
1497 	/* Free the properties */
1498 	lut_free(ep->props, instances_destructor, NULL);
1499 
1500 	/* Free my bubbles */
1501 	for (bub = ep->bubbles; bub != NULL; ) {
1502 		nextbub = bub->next;
1503 		/*
1504 		 * Free arrows if they are FROM me.  Free arrowlists on
1505 		 * other types of bubbles (but not the attached arrows,
1506 		 * which will be freed when we free the originating
1507 		 * bubble.
1508 		 */
1509 		if (bub->t == B_FROM)
1510 			itree_free_arrowlists(bub, 1);
1511 		else
1512 			itree_free_arrowlists(bub, 0);
1513 		itree_free_bubble(bub);
1514 		bub = nextbub;
1515 	}
1516 
1517 	if (ep->nvp != NULL)
1518 		nvlist_free(ep->nvp);
1519 	bzero(ep, sizeof (*ep));
1520 	FREE(ep);
1521 }
1522 
1523 static void
1524 itree_free_bubble(struct bubble *freeme)
1525 {
1526 	bzero(freeme, sizeof (*freeme));
1527 	FREE(freeme);
1528 }
1529 
1530 static struct bubble *
1531 itree_add_bubble(struct event *eventp, enum bubbletype btype, int nork, int gen)
1532 {
1533 	struct bubble *prev = NULL;
1534 	struct bubble *curr;
1535 	struct bubble *newb;
1536 
1537 	/* Use existing bubbles as appropriate when possible */
1538 	for (curr = eventp->bubbles;
1539 	    curr != NULL;
1540 	    prev = curr, curr = curr->next) {
1541 		if (btype == B_TO && curr->t == B_TO) {
1542 			/* see if an existing "to" bubble works for us */
1543 			if (gen == curr->gen)
1544 				return (curr);	/* matched gen number */
1545 			else if (nork == 1 && curr->nork == 1) {
1546 				curr->gen = gen;
1547 				return (curr);	/* coalesce K==1 bubbles */
1548 			}
1549 		} else if (btype == B_FROM && curr->t == B_FROM) {
1550 			/* see if an existing "from" bubble works for us */
1551 			if ((nork == N_IS_ALL && curr->nork == N_IS_ALL) ||
1552 			    (nork == 0 && curr->nork == 0))
1553 				return (curr);
1554 		}
1555 	}
1556 
1557 	newb = MALLOC(sizeof (struct bubble));
1558 	newb->next = NULL;
1559 	newb->t = btype;
1560 	newb->myevent = eventp;
1561 	newb->nork = nork;
1562 	newb->mark = 0;
1563 	newb->gen = gen;
1564 	newb->arrows = NULL;
1565 
1566 	if (prev == NULL)
1567 		eventp->bubbles = newb;
1568 	else
1569 		prev->next = newb;
1570 
1571 	return (newb);
1572 }
1573 
1574 struct bubble *
1575 itree_next_bubble(struct event *eventp, struct bubble *last)
1576 {
1577 	struct bubble *next;
1578 
1579 	for (;;) {
1580 		if (last != NULL)
1581 			next = last->next;
1582 		else
1583 			next = eventp->bubbles;
1584 
1585 		if (next == NULL || next->arrows != NULL)
1586 			return (next);
1587 
1588 		/* bubble was empty, skip it */
1589 		last = next;
1590 	}
1591 }
1592 
1593 static void
1594 add_arrow(struct bubble *bp, struct arrow *ap)
1595 {
1596 	struct arrowlist *prev = NULL;
1597 	struct arrowlist *curr;
1598 	struct arrowlist *newal;
1599 
1600 	newal = MALLOC(sizeof (struct arrowlist));
1601 	bzero(newal, sizeof (struct arrowlist));
1602 	newal->arrowp = ap;
1603 
1604 	curr = itree_next_arrow(bp, NULL);
1605 	while (curr != NULL) {
1606 		prev = curr;
1607 		curr = itree_next_arrow(bp, curr);
1608 	}
1609 
1610 	if (prev == NULL)
1611 		bp->arrows = newal;
1612 	else
1613 		prev->next = newal;
1614 }
1615 
1616 static struct arrow *
1617 itree_add_arrow(struct bubble *frombubblep, struct bubble *tobubblep,
1618     struct node *apnode, struct node *fromevent, struct node *toevent,
1619     struct lut *ex)
1620 {
1621 	struct arrow *newa;
1622 
1623 	ASSERTeq(frombubblep->t, B_FROM, itree_bubbletype2str);
1624 	ASSERTinfo(tobubblep->t == B_TO || tobubblep->t == B_INHIBIT,
1625 	    itree_bubbletype2str(tobubblep->t));
1626 	newa = MALLOC(sizeof (struct arrow));
1627 	newa->tail = frombubblep;
1628 	newa->head = tobubblep;
1629 	newa->pnode = apnode;
1630 	newa->constraints = NULL;
1631 
1632 	/*
1633 	 *  Set default delays, then try to re-set them from
1634 	 *  any within() constraints.
1635 	 */
1636 	newa->mindelay = newa->maxdelay = 0ULL;
1637 	if (itree_set_arrow_traits(newa, fromevent, toevent, ex) == 0) {
1638 		FREE(newa);
1639 		return (NULL);
1640 	}
1641 
1642 	add_arrow(frombubblep, newa);
1643 	add_arrow(tobubblep, newa);
1644 	return (newa);
1645 }
1646 
1647 /* returns false if traits show that arrow should not be added after all */
1648 static int
1649 itree_set_arrow_traits(struct arrow *ap, struct node *fromev,
1650     struct node *toev, struct lut *ex)
1651 {
1652 	struct node *epnames[] = { NULL, NULL, NULL };
1653 	struct node *newc = NULL;
1654 
1655 	ASSERTeq(fromev->t, T_EVENT, ptree_nodetype2str);
1656 	ASSERTeq(toev->t, T_EVENT, ptree_nodetype2str);
1657 
1658 	/*
1659 	 * search for the within values first on the declaration of
1660 	 * the destination event, and then on the prop.  this allows
1661 	 * one to specify a "default" within by putting it on the
1662 	 * declaration,  but then allow overriding on the prop statement.
1663 	 */
1664 	arrow_add_within(ap, toev->u.event.declp->u.stmt.np->u.event.eexprlist);
1665 	arrow_add_within(ap, toev->u.event.eexprlist);
1666 
1667 	/*
1668 	 * handle any global constraints inherited from the
1669 	 * "fromev" event's declaration
1670 	 */
1671 	ASSERT(fromev->u.event.declp != NULL);
1672 	ASSERT(fromev->u.event.declp->u.stmt.np != NULL);
1673 
1674 #ifdef	notdef
1675 	/* XXX not quite ready to evaluate constraints from decls yet */
1676 	if (fromev->u.event.declp->u.stmt.np->u.event.eexprlist)
1677 		(void) itree_add_constraint(ap,
1678 		    fromev->u.event.declp->u.stmt.np->u.event.eexprlist);
1679 #endif	/* notdef */
1680 
1681 	/* handle constraints on the from event in the prop statement */
1682 	epnames[0] = fromev->u.event.epname;
1683 	epnames[1] = toev->u.event.epname;
1684 	if (eval_potential(fromev->u.event.eexprlist, ex, epnames, &newc) == 0)
1685 		return (0);		/* constraint disallows arrow */
1686 
1687 	/*
1688 	 * handle any global constraints inherited from the
1689 	 * "toev" event's declaration
1690 	 */
1691 	ASSERT(toev->u.event.declp != NULL);
1692 	ASSERT(toev->u.event.declp->u.stmt.np != NULL);
1693 
1694 #ifdef	notdef
1695 	/* XXX not quite ready to evaluate constraints from decls yet */
1696 	if (toev->u.event.declp->u.stmt.np->u.event.eexprlist)
1697 		(void) itree_add_constraint(ap,
1698 		    toev->u.event.declp->u.stmt.np->u.event.eexprlist);
1699 #endif	/* notdef */
1700 
1701 	/* handle constraints on the to event in the prop statement */
1702 	epnames[0] = toev->u.event.epname;
1703 	epnames[1] = fromev->u.event.epname;
1704 	if (eval_potential(toev->u.event.eexprlist, ex, epnames, &newc) == 0)
1705 		return (0);		/* constraint disallows arrow */
1706 
1707 	/* if we came up with any deferred constraints, add them to arrow */
1708 	if (newc != NULL)
1709 		(void) itree_add_constraint(ap, newc);
1710 
1711 	return (1);	/* constraints allow arrow */
1712 }
1713 
1714 /*
1715  * Set within() constraint.  If the constraint were set multiple times,
1716  * the last one would "win".
1717  */
1718 static void
1719 arrow_add_within(struct arrow *ap, struct node *xpr)
1720 {
1721 	struct node *arglist;
1722 
1723 	/* end of expressions list */
1724 	if (xpr == NULL)
1725 		return;
1726 
1727 	switch (xpr->t) {
1728 	case T_LIST:
1729 		arrow_add_within(ap, xpr->u.expr.left);
1730 		arrow_add_within(ap, xpr->u.expr.right);
1731 		return;
1732 	case T_FUNC:
1733 		if (xpr->u.func.s != L_within)
1734 			return;
1735 		arglist = xpr->u.func.arglist;
1736 		switch (arglist->t) {
1737 		case T_TIMEVAL:
1738 			ap->mindelay = 0;
1739 			ap->maxdelay = arglist->u.ull;
1740 			break;
1741 		case T_NAME:
1742 			ASSERT(arglist->u.name.s == L_infinity);
1743 			ap->mindelay = 0;
1744 			ap->maxdelay = TIMEVAL_EVENTUALLY;
1745 			break;
1746 		case T_LIST:
1747 			ASSERT(arglist->u.expr.left->t == T_TIMEVAL);
1748 			ap->mindelay = arglist->u.expr.left->u.ull;
1749 			switch (arglist->u.expr.right->t) {
1750 			case T_TIMEVAL:
1751 				ap->maxdelay = arglist->u.ull;
1752 				break;
1753 			case T_NAME:
1754 				ASSERT(arglist->u.expr.right->u.name.s ==
1755 				    L_infinity);
1756 				ap->maxdelay = TIMEVAL_EVENTUALLY;
1757 				break;
1758 			default:
1759 				out(O_DIE, "within: unexpected 2nd arg type");
1760 			}
1761 			break;
1762 		default:
1763 			out(O_DIE, "within: unexpected 1st arg type");
1764 		}
1765 		break;
1766 	default:
1767 		return;
1768 	}
1769 }
1770 
1771 static void
1772 itree_free_arrowlists(struct bubble *bubp, int arrows_too)
1773 {
1774 	struct arrowlist *al, *nal;
1775 
1776 	al = bubp->arrows;
1777 	while (al != NULL) {
1778 		nal = al->next;
1779 		if (arrows_too) {
1780 			itree_free_constraints(al->arrowp);
1781 			bzero(al->arrowp, sizeof (struct arrow));
1782 			FREE(al->arrowp);
1783 		}
1784 		bzero(al, sizeof (*al));
1785 		FREE(al);
1786 		al = nal;
1787 	}
1788 }
1789 
1790 struct arrowlist *
1791 itree_next_arrow(struct bubble *bubble, struct arrowlist *last)
1792 {
1793 	struct arrowlist *next;
1794 
1795 	if (last != NULL)
1796 		next = last->next;
1797 	else
1798 		next = bubble->arrows;
1799 	return (next);
1800 }
1801 
1802 static struct constraintlist *
1803 itree_add_constraint(struct arrow *arrowp, struct node *c)
1804 {
1805 	struct constraintlist *prev = NULL;
1806 	struct constraintlist *curr;
1807 	struct constraintlist *newc;
1808 
1809 	for (curr = arrowp->constraints;
1810 	    curr != NULL;
1811 	    prev = curr, curr = curr->next);
1812 
1813 	newc = MALLOC(sizeof (struct constraintlist));
1814 	newc->next = NULL;
1815 	newc->cnode = c;
1816 
1817 	if (prev == NULL)
1818 		arrowp->constraints = newc;
1819 	else
1820 		prev->next = newc;
1821 
1822 	return (newc);
1823 }
1824 
1825 struct constraintlist *
1826 itree_next_constraint(struct arrow *arrowp, struct constraintlist *last)
1827 {
1828 	struct constraintlist *next;
1829 
1830 	if (last != NULL)
1831 		next = last->next;
1832 	else
1833 		next = arrowp->constraints;
1834 	return (next);
1835 }
1836 
1837 static void
1838 itree_free_constraints(struct arrow *ap)
1839 {
1840 	struct constraintlist *cl, *ncl;
1841 
1842 	cl = ap->constraints;
1843 	while (cl != NULL) {
1844 		ncl = cl->next;
1845 		ASSERT(cl->cnode != NULL);
1846 		tree_free(cl->cnode);
1847 		bzero(cl, sizeof (*cl));
1848 		FREE(cl);
1849 		cl = ncl;
1850 	}
1851 }
1852 
1853 const char *
1854 itree_bubbletype2str(enum bubbletype t)
1855 {
1856 	static char buf[100];
1857 
1858 	switch (t) {
1859 	case B_FROM:	return L_from;
1860 	case B_TO:	return L_to;
1861 	case B_INHIBIT:	return L_inhibit;
1862 	default:
1863 		(void) sprintf(buf, "[unexpected bubbletype: %d]", t);
1864 		return (buf);
1865 	}
1866 }
1867 
1868 /*
1869  * itree_fini -- clean up any half-built itrees
1870  */
1871 void
1872 itree_fini(void)
1873 {
1874 	if (Ninfo.lut != NULL) {
1875 		itree_free(Ninfo.lut);
1876 		Ninfo.lut = NULL;
1877 	}
1878 	if (Ninfo.ex) {
1879 		lut_free(Ninfo.ex, iterinfo_destructor, NULL);
1880 		Ninfo.ex = NULL;
1881 	}
1882 }
1883