10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51717Swesolows * Common Development and Distribution License (the "License").
61717Swesolows * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
211717Swesolows
220Sstevel@tonic-gate /*
239874SStephen.Hanson@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate *
260Sstevel@tonic-gate * itree.c -- instance tree creation and manipulation
270Sstevel@tonic-gate *
280Sstevel@tonic-gate * this module provides the instance tree
290Sstevel@tonic-gate */
300Sstevel@tonic-gate
310Sstevel@tonic-gate #include <stdio.h>
320Sstevel@tonic-gate #include <ctype.h>
330Sstevel@tonic-gate #include <string.h>
340Sstevel@tonic-gate #include <strings.h>
350Sstevel@tonic-gate #include "alloc.h"
360Sstevel@tonic-gate #include "out.h"
370Sstevel@tonic-gate #include "stable.h"
380Sstevel@tonic-gate #include "literals.h"
390Sstevel@tonic-gate #include "lut.h"
400Sstevel@tonic-gate #include "tree.h"
410Sstevel@tonic-gate #include "ptree.h"
420Sstevel@tonic-gate #include "itree.h"
430Sstevel@tonic-gate #include "ipath.h"
441414Scindi #include "iexpr.h"
450Sstevel@tonic-gate #include "eval.h"
460Sstevel@tonic-gate #include "config.h"
470Sstevel@tonic-gate
480Sstevel@tonic-gate /*
490Sstevel@tonic-gate * struct info contains the state we keep when expanding a prop statement
500Sstevel@tonic-gate * as part of constructing the instance tree. state kept in struct info
510Sstevel@tonic-gate * is the non-recursive stuff -- the stuff that doesn't need to be on
520Sstevel@tonic-gate * the stack. the rest of the state that is passed between all the
530Sstevel@tonic-gate * mutually recursive functions, is required to be on the stack since
540Sstevel@tonic-gate * we need to backtrack and recurse as we do the instance tree construction.
550Sstevel@tonic-gate */
560Sstevel@tonic-gate struct info {
570Sstevel@tonic-gate struct lut *lut;
580Sstevel@tonic-gate struct node *anp; /* arrow np */
590Sstevel@tonic-gate struct lut *ex; /* dictionary of explicit iterators */
600Sstevel@tonic-gate struct config *croot;
610Sstevel@tonic-gate } Ninfo;
620Sstevel@tonic-gate
630Sstevel@tonic-gate /*
640Sstevel@tonic-gate * struct wildcardinfo is used to track wildcarded portions of paths.
650Sstevel@tonic-gate *
660Sstevel@tonic-gate * for example, if the epname of an event is "c/d" and the path "a/b/c/d"
670Sstevel@tonic-gate * exists, the wildcard path ewname is filled in with the path "a/b". when
680Sstevel@tonic-gate * matching is done, epname is temporarily replaced with the concatenation
694436Sstephh * of ewname and epname.
700Sstevel@tonic-gate *
710Sstevel@tonic-gate * a linked list of these structs is used to track the expansion of each
720Sstevel@tonic-gate * event node as it is processed in vmatch() --> vmatch_event() calls.
730Sstevel@tonic-gate */
740Sstevel@tonic-gate struct wildcardinfo {
750Sstevel@tonic-gate struct node *nptop; /* event node fed to vmatch */
760Sstevel@tonic-gate struct node *oldepname; /* epname without the wildcard part */
774436Sstephh struct node *ewname; /* wildcard path */
78*10146SStephen.Hanson@Sun.COM int got_wc_hz;
790Sstevel@tonic-gate struct wildcardinfo *next;
800Sstevel@tonic-gate };
810Sstevel@tonic-gate
824436Sstephh static struct wildcardinfo *wcproot = NULL;
834436Sstephh
844436Sstephh static void vmatch(struct info *infop, struct node *np, struct node *lnp,
854436Sstephh struct node *anp);
860Sstevel@tonic-gate static void hmatch(struct info *infop, struct node *np, struct node *nextnp);
87*10146SStephen.Hanson@Sun.COM static void hmatch_event(struct info *infop, struct node *eventnp,
88*10146SStephen.Hanson@Sun.COM struct node *epname, struct config *ncp, struct node *nextnp, int rematch);
890Sstevel@tonic-gate static void itree_pbubble(int flags, struct bubble *bp);
901865Sdilpreet static void itree_pruner(void *left, void *right, void *arg);
910Sstevel@tonic-gate static void itree_destructor(void *left, void *right, void *arg);
920Sstevel@tonic-gate static int itree_set_arrow_traits(struct arrow *ap, struct node *fromev,
930Sstevel@tonic-gate struct node *toev, struct lut *ex);
940Sstevel@tonic-gate static void itree_free_arrowlists(struct bubble *bubp, int arrows_too);
951865Sdilpreet static void itree_prune_arrowlists(struct bubble *bubp);
960Sstevel@tonic-gate static void arrow_add_within(struct arrow *ap, struct node *xpr);
974436Sstephh static struct arrow *itree_add_arrow(struct node *apnode,
984436Sstephh struct node *fromevent, struct node *toevent, struct lut *ex);
994436Sstephh static struct event *find_or_add_event(struct info *infop, struct node *np);
1004436Sstephh static void add_arrow(struct bubble *bp, struct arrow *ap);
1010Sstevel@tonic-gate static struct constraintlist *itree_add_constraint(struct arrow *arrowp,
1020Sstevel@tonic-gate struct node *c);
1030Sstevel@tonic-gate static struct bubble *itree_add_bubble(struct event *eventp,
1040Sstevel@tonic-gate enum bubbletype btype, int nork, int gen);
1050Sstevel@tonic-gate static void itree_free_bubble(struct bubble *freeme);
1060Sstevel@tonic-gate static void itree_free_constraints(struct arrow *ap);
1070Sstevel@tonic-gate
1080Sstevel@tonic-gate /*
1090Sstevel@tonic-gate * the following struct contains the state we build up during
1100Sstevel@tonic-gate * vertical and horizontal expansion so that generate()
1110Sstevel@tonic-gate * has everything it needs to construct the appropriate arrows.
1120Sstevel@tonic-gate * after setting up the state by calling:
1130Sstevel@tonic-gate * generate_arrownp()
1140Sstevel@tonic-gate * generate_nork()
1150Sstevel@tonic-gate * generate_new()
1160Sstevel@tonic-gate * generate_from()
1170Sstevel@tonic-gate * generate_to()
1180Sstevel@tonic-gate * the actual arrow generation is done by calling:
1190Sstevel@tonic-gate * generate()
1200Sstevel@tonic-gate */
1210Sstevel@tonic-gate static struct {
1220Sstevel@tonic-gate int generation; /* generation number of arrow set */
1237197Sstephh int matched; /* number of matches */
1240Sstevel@tonic-gate struct node *arrownp; /* top-level parse tree for arrow */
1250Sstevel@tonic-gate int n; /* n value associated with arrow */
1260Sstevel@tonic-gate int k; /* k value associated with arrow */
1270Sstevel@tonic-gate struct node *fromnp; /* left-hand-side event in parse tree */
1280Sstevel@tonic-gate struct node *tonp; /* right-hand-side event in parse tree */
1290Sstevel@tonic-gate struct event *frome; /* left-hand-side event in instance tree */
1300Sstevel@tonic-gate struct event *toe; /* right-hand-side event in instance tree */
1310Sstevel@tonic-gate struct bubble *frombp; /* bubble arrow comes from */
1320Sstevel@tonic-gate struct bubble *tobp; /* bubble arrow goes to */
1330Sstevel@tonic-gate } G;
1340Sstevel@tonic-gate
1350Sstevel@tonic-gate static void
generate_arrownp(struct node * arrownp)1360Sstevel@tonic-gate generate_arrownp(struct node *arrownp)
1370Sstevel@tonic-gate {
1380Sstevel@tonic-gate G.arrownp = arrownp;
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate static void
generate_nork(int n,int k)1420Sstevel@tonic-gate generate_nork(int n, int k)
1430Sstevel@tonic-gate {
1440Sstevel@tonic-gate G.n = n;
1450Sstevel@tonic-gate G.k = k;
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate static void
generate_new(void)1490Sstevel@tonic-gate generate_new(void)
1500Sstevel@tonic-gate {
1510Sstevel@tonic-gate G.generation++;
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate static void
generate_from(struct node * fromeventnp)1554436Sstephh generate_from(struct node *fromeventnp)
1560Sstevel@tonic-gate {
1574436Sstephh G.frombp = NULL;
1580Sstevel@tonic-gate G.fromnp = fromeventnp;
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate static void
generate_to(struct node * toeventnp)1624436Sstephh generate_to(struct node *toeventnp)
1630Sstevel@tonic-gate {
1640Sstevel@tonic-gate G.tonp = toeventnp;
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate static void
generate(struct info * infop)1684436Sstephh generate(struct info *infop)
1690Sstevel@tonic-gate {
1704436Sstephh struct arrow *arrowp;
1714436Sstephh
1720Sstevel@tonic-gate ASSERT(G.arrownp != NULL);
1730Sstevel@tonic-gate ASSERT(G.fromnp != NULL);
1740Sstevel@tonic-gate ASSERT(G.tonp != NULL);
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate out(O_ALTFP|O_VERB3|O_NONL, " Arrow \"");
1770Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.fromnp);
1780Sstevel@tonic-gate out(O_ALTFP|O_VERB3|O_NONL, "\" -> \"");
1790Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.tonp);
1804436Sstephh out(O_ALTFP|O_VERB3|O_NONL, "\" ");
1810Sstevel@tonic-gate
1824436Sstephh arrowp = itree_add_arrow(G.arrownp, G.fromnp, G.tonp, infop->ex);
1834436Sstephh if (arrowp == NULL) {
1844436Sstephh out(O_ALTFP|O_VERB3, "(prevented by constraints)");
1850Sstevel@tonic-gate } else {
1864436Sstephh out(O_ALTFP|O_VERB3, "");
1874436Sstephh if (!G.frombp) {
1884436Sstephh G.frome = find_or_add_event(infop, G.fromnp);
1894436Sstephh G.frombp = itree_add_bubble(G.frome, B_FROM, G.n, 0);
1904436Sstephh }
1914436Sstephh G.toe = find_or_add_event(infop, G.tonp);
1924436Sstephh G.tobp = itree_add_bubble(G.toe, B_TO, G.k, G.generation);
1934436Sstephh arrowp->tail = G.frombp;
1944436Sstephh arrowp->head = G.tobp;
1954436Sstephh add_arrow(G.frombp, arrowp);
1964436Sstephh add_arrow(G.tobp, arrowp);
1970Sstevel@tonic-gate }
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate enum childnode_action {
2010Sstevel@tonic-gate CN_NONE,
2020Sstevel@tonic-gate CN_DUP
2030Sstevel@tonic-gate };
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate static struct node *
tname_dup(struct node * namep,enum childnode_action act)2060Sstevel@tonic-gate tname_dup(struct node *namep, enum childnode_action act)
2070Sstevel@tonic-gate {
2080Sstevel@tonic-gate struct node *retp = NULL;
2090Sstevel@tonic-gate const char *file;
2100Sstevel@tonic-gate int line;
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate if (namep == NULL)
2130Sstevel@tonic-gate return (NULL);
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate file = namep->file;
2160Sstevel@tonic-gate line = namep->line;
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate for (; namep != NULL; namep = namep->u.name.next) {
2190Sstevel@tonic-gate struct node *newnp = newnode(T_NAME, file, line);
2200Sstevel@tonic-gate
2210Sstevel@tonic-gate newnp->u.name.t = namep->u.name.t;
2220Sstevel@tonic-gate newnp->u.name.s = namep->u.name.s;
2230Sstevel@tonic-gate newnp->u.name.last = newnp;
2240Sstevel@tonic-gate newnp->u.name.it = namep->u.name.it;
2250Sstevel@tonic-gate newnp->u.name.cp = namep->u.name.cp;
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate if (act == CN_DUP) {
2280Sstevel@tonic-gate struct node *npc;
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate npc = namep->u.name.child;
2310Sstevel@tonic-gate if (npc != NULL) {
2320Sstevel@tonic-gate switch (npc->t) {
2330Sstevel@tonic-gate case T_NUM:
2340Sstevel@tonic-gate newnp->u.name.child =
2354436Sstephh newnode(T_NUM, file, line);
2360Sstevel@tonic-gate newnp->u.name.child->u.ull =
2374436Sstephh npc->u.ull;
2380Sstevel@tonic-gate break;
2390Sstevel@tonic-gate case T_NAME:
2400Sstevel@tonic-gate newnp->u.name.child =
2414436Sstephh tree_name(npc->u.name.s,
2424436Sstephh npc->u.name.it, file, line);
2430Sstevel@tonic-gate break;
2440Sstevel@tonic-gate default:
2450Sstevel@tonic-gate out(O_DIE, "tname_dup: "
2460Sstevel@tonic-gate "invalid child type %s",
2470Sstevel@tonic-gate ptree_nodetype2str(npc->t));
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate }
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate if (retp == NULL) {
2530Sstevel@tonic-gate retp = newnp;
2540Sstevel@tonic-gate } else {
2550Sstevel@tonic-gate retp->u.name.last->u.name.next = newnp;
2560Sstevel@tonic-gate retp->u.name.last = newnp;
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate return (retp);
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate struct prop_wlk_data {
2640Sstevel@tonic-gate struct lut *props;
2650Sstevel@tonic-gate struct node *epname;
2660Sstevel@tonic-gate };
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate static struct lut *props2instance(struct node *, struct node *);
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate /*
2710Sstevel@tonic-gate * let oldepname be a subset of epname. return the subsection of epname
2720Sstevel@tonic-gate * that ends with oldepname. make each component in the path explicitly
2730Sstevel@tonic-gate * instanced (i.e., with a T_NUM child).
2740Sstevel@tonic-gate */
2750Sstevel@tonic-gate static struct node *
tname_dup_to_epname(struct node * oldepname,struct node * epname)2760Sstevel@tonic-gate tname_dup_to_epname(struct node *oldepname, struct node *epname)
2770Sstevel@tonic-gate {
2780Sstevel@tonic-gate struct node *npref, *npend, *np1, *np2;
2790Sstevel@tonic-gate struct node *ret = NULL;
2800Sstevel@tonic-gate int foundmatch = 0;
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate if (epname == NULL)
2830Sstevel@tonic-gate return (NULL);
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate /*
2860Sstevel@tonic-gate * search for the longest path in epname which contains
2870Sstevel@tonic-gate * oldnode->u.event.epname. set npend to point to just past the
2880Sstevel@tonic-gate * end of this path.
2890Sstevel@tonic-gate */
2900Sstevel@tonic-gate npend = NULL;
2910Sstevel@tonic-gate for (npref = epname; npref; npref = npref->u.name.next) {
2920Sstevel@tonic-gate if (npref->u.name.s == oldepname->u.name.s) {
2930Sstevel@tonic-gate for (np1 = npref, np2 = oldepname;
2940Sstevel@tonic-gate np1 != NULL && np2 != NULL;
2950Sstevel@tonic-gate np1 = np1->u.name.next, np2 = np2->u.name.next) {
2960Sstevel@tonic-gate if (np1->u.name.s != np2->u.name.s)
2970Sstevel@tonic-gate break;
2980Sstevel@tonic-gate }
2990Sstevel@tonic-gate if (np2 == NULL) {
3000Sstevel@tonic-gate foundmatch = 1;
3010Sstevel@tonic-gate npend = np1;
3020Sstevel@tonic-gate if (np1 == NULL) {
3030Sstevel@tonic-gate /* oldepname matched npref up to end */
3040Sstevel@tonic-gate break;
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate if (foundmatch == 0) {
3110Sstevel@tonic-gate /*
3120Sstevel@tonic-gate * if oldepname could not be found in epname, return a
3130Sstevel@tonic-gate * duplicate of the former. do not try to instantize
3140Sstevel@tonic-gate * oldepname since it might not be a path.
3150Sstevel@tonic-gate */
3160Sstevel@tonic-gate return (tname_dup(oldepname, CN_DUP));
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate
3190Sstevel@tonic-gate /*
3200Sstevel@tonic-gate * dup (epname -- npend). all children should be T_NUMs.
3210Sstevel@tonic-gate */
3220Sstevel@tonic-gate for (npref = epname;
3230Sstevel@tonic-gate ! (npref == NULL || npref == npend);
3240Sstevel@tonic-gate npref = npref->u.name.next) {
3250Sstevel@tonic-gate struct node *newnp = newnode(T_NAME, oldepname->file,
3264436Sstephh oldepname->line);
3270Sstevel@tonic-gate
3280Sstevel@tonic-gate newnp->u.name.t = npref->u.name.t;
3290Sstevel@tonic-gate newnp->u.name.s = npref->u.name.s;
3300Sstevel@tonic-gate newnp->u.name.last = newnp;
3310Sstevel@tonic-gate newnp->u.name.it = npref->u.name.it;
3320Sstevel@tonic-gate newnp->u.name.cp = npref->u.name.cp;
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate newnp->u.name.child = newnode(T_NUM, oldepname->file,
3354436Sstephh oldepname->line);
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate if (npref->u.name.child == NULL ||
3380Sstevel@tonic-gate npref->u.name.child->t != T_NUM) {
3390Sstevel@tonic-gate int childnum;
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate ASSERT(npref->u.name.cp != NULL);
3420Sstevel@tonic-gate config_getcompname(npref->u.name.cp, NULL, &childnum);
3430Sstevel@tonic-gate newnp->u.name.child->u.ull = childnum;
3440Sstevel@tonic-gate } else {
3450Sstevel@tonic-gate newnp->u.name.child->u.ull =
3464436Sstephh npref->u.name.child->u.ull;
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate if (ret == NULL) {
3500Sstevel@tonic-gate ret = newnp;
3510Sstevel@tonic-gate } else {
3520Sstevel@tonic-gate ret->u.name.last->u.name.next = newnp;
3530Sstevel@tonic-gate ret->u.name.last = newnp;
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate
3570Sstevel@tonic-gate return (ret);
3580Sstevel@tonic-gate }
3590Sstevel@tonic-gate
3600Sstevel@tonic-gate /*
3610Sstevel@tonic-gate * restriction: oldnode->u.event.epname has to be equivalent to or a subset
3620Sstevel@tonic-gate * of epname
3630Sstevel@tonic-gate */
3640Sstevel@tonic-gate static struct node *
tevent_dup_to_epname(struct node * oldnode,struct node * epname)3650Sstevel@tonic-gate tevent_dup_to_epname(struct node *oldnode, struct node *epname)
3660Sstevel@tonic-gate {
3670Sstevel@tonic-gate struct node *ret;
3680Sstevel@tonic-gate
3690Sstevel@tonic-gate ret = newnode(T_EVENT, oldnode->file, oldnode->line);
3700Sstevel@tonic-gate ret->u.event.ename = tname_dup(oldnode->u.event.ename, CN_NONE);
3710Sstevel@tonic-gate ret->u.event.epname = tname_dup_to_epname(oldnode->u.event.epname,
3724436Sstephh epname);
3730Sstevel@tonic-gate return (ret);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate static void
nv_instantiate(void * name,void * val,void * arg)3770Sstevel@tonic-gate nv_instantiate(void *name, void *val, void *arg)
3780Sstevel@tonic-gate {
3790Sstevel@tonic-gate struct prop_wlk_data *pd = (struct prop_wlk_data *)arg;
3800Sstevel@tonic-gate struct node *orhs = (struct node *)val;
3810Sstevel@tonic-gate struct node *nrhs;
3820Sstevel@tonic-gate
3830Sstevel@tonic-gate /* handle engines by instantizing the entire engine */
3840Sstevel@tonic-gate if (name == L_engine) {
3850Sstevel@tonic-gate ASSERT(orhs->t == T_EVENT);
3860Sstevel@tonic-gate ASSERT(orhs->u.event.ename->u.name.t == N_SERD);
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate /* there are only SERD engines for now */
3890Sstevel@tonic-gate
3900Sstevel@tonic-gate nrhs = newnode(T_SERD, orhs->file, orhs->line);
3910Sstevel@tonic-gate nrhs->u.stmt.np = tevent_dup_to_epname(orhs, pd->epname);
3920Sstevel@tonic-gate nrhs->u.stmt.lutp = props2instance(orhs, pd->epname);
3930Sstevel@tonic-gate pd->props = lut_add(pd->props, name, nrhs, NULL);
3940Sstevel@tonic-gate return;
3950Sstevel@tonic-gate }
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate switch (orhs->t) {
3980Sstevel@tonic-gate case T_NUM:
3990Sstevel@tonic-gate nrhs = newnode(T_NUM, orhs->file, orhs->line);
4000Sstevel@tonic-gate nrhs->u.ull = orhs->u.ull;
4010Sstevel@tonic-gate pd->props = lut_add(pd->props, name, nrhs, NULL);
4020Sstevel@tonic-gate break;
4030Sstevel@tonic-gate case T_TIMEVAL:
4040Sstevel@tonic-gate nrhs = newnode(T_TIMEVAL, orhs->file, orhs->line);
4050Sstevel@tonic-gate nrhs->u.ull = orhs->u.ull;
4060Sstevel@tonic-gate pd->props = lut_add(pd->props, name, nrhs, NULL);
4070Sstevel@tonic-gate break;
4080Sstevel@tonic-gate case T_NAME:
4090Sstevel@tonic-gate nrhs = tname_dup_to_epname(orhs, pd->epname);
4100Sstevel@tonic-gate pd->props = lut_add(pd->props, name, nrhs, NULL);
4110Sstevel@tonic-gate break;
4120Sstevel@tonic-gate case T_EVENT:
4130Sstevel@tonic-gate nrhs = tevent_dup_to_epname(orhs, pd->epname);
4140Sstevel@tonic-gate pd->props = lut_add(pd->props, name, nrhs, NULL);
4150Sstevel@tonic-gate break;
4161414Scindi case T_GLOBID:
4171414Scindi nrhs = newnode(T_GLOBID, orhs->file, orhs->line);
4181414Scindi nrhs->u.globid.s = orhs->u.globid.s;
4191414Scindi pd->props = lut_add(pd->props, name, nrhs, NULL);
4201414Scindi break;
4211414Scindi case T_FUNC:
4221414Scindi /* for T_FUNC, we don't duplicate it, just point to node */
4231414Scindi pd->props = lut_add(pd->props, name, orhs, NULL);
4241414Scindi break;
4250Sstevel@tonic-gate default:
4261414Scindi out(O_DIE, "unexpected nvpair value type %s",
4270Sstevel@tonic-gate ptree_nodetype2str(((struct node *)val)->t));
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate }
4300Sstevel@tonic-gate
4310Sstevel@tonic-gate static struct lut *
props2instance(struct node * eventnp,struct node * epname)4320Sstevel@tonic-gate props2instance(struct node *eventnp, struct node *epname)
4330Sstevel@tonic-gate {
4340Sstevel@tonic-gate struct prop_wlk_data pd;
4350Sstevel@tonic-gate
4360Sstevel@tonic-gate pd.props = NULL;
4370Sstevel@tonic-gate pd.epname = epname;
4380Sstevel@tonic-gate
4390Sstevel@tonic-gate ASSERT(eventnp->u.event.declp != NULL);
4400Sstevel@tonic-gate lut_walk(eventnp->u.event.declp->u.stmt.lutp, nv_instantiate, &pd);
4410Sstevel@tonic-gate return (pd.props);
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate
4440Sstevel@tonic-gate /*ARGSUSED*/
4450Sstevel@tonic-gate static void
instances_destructor(void * left,void * right,void * arg)4460Sstevel@tonic-gate instances_destructor(void *left, void *right, void *arg)
4470Sstevel@tonic-gate {
4480Sstevel@tonic-gate struct node *dn = (struct node *)right;
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate if (dn->t == T_SERD) {
4510Sstevel@tonic-gate /* we allocated the lut during itree_create(), so free it */
4520Sstevel@tonic-gate lut_free(dn->u.stmt.lutp, instances_destructor, NULL);
4530Sstevel@tonic-gate dn->u.stmt.lutp = NULL;
4540Sstevel@tonic-gate }
4551414Scindi if (dn->t != T_FUNC) /* T_FUNC pointed to original node */
4561414Scindi tree_free(dn);
4571414Scindi }
4581414Scindi
4591414Scindi /*ARGSUSED*/
4601414Scindi static void
payloadprops_destructor(void * left,void * right,void * arg)4611414Scindi payloadprops_destructor(void *left, void *right, void *arg)
4621414Scindi {
4631414Scindi FREE(right);
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate
4667197Sstephh /*ARGSUSED*/
4677197Sstephh static void
serdprops_destructor(void * left,void * right,void * arg)4687197Sstephh serdprops_destructor(void *left, void *right, void *arg)
4697197Sstephh {
4707197Sstephh FREE(right);
4717197Sstephh }
4727197Sstephh
4730Sstevel@tonic-gate /*
4740Sstevel@tonic-gate * event_cmp -- used via lut_lookup/lut_add on instance tree lut
4750Sstevel@tonic-gate */
4760Sstevel@tonic-gate static int
event_cmp(struct event * ep1,struct event * ep2)4770Sstevel@tonic-gate event_cmp(struct event *ep1, struct event *ep2)
4780Sstevel@tonic-gate {
4790Sstevel@tonic-gate int diff;
4800Sstevel@tonic-gate
4810Sstevel@tonic-gate if ((diff = ep2->enode->u.event.ename->u.name.s -
4820Sstevel@tonic-gate ep1->enode->u.event.ename->u.name.s) != 0)
4830Sstevel@tonic-gate return (diff);
4840Sstevel@tonic-gate if ((diff = (char *)ep2->ipp - (char *)ep1->ipp) != 0)
4850Sstevel@tonic-gate return (diff);
4860Sstevel@tonic-gate return (0);
4870Sstevel@tonic-gate
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate struct event *
itree_lookup(struct lut * itp,const char * ename,const struct ipath * ipp)4910Sstevel@tonic-gate itree_lookup(struct lut *itp, const char *ename, const struct ipath *ipp)
4920Sstevel@tonic-gate {
4930Sstevel@tonic-gate struct event searchevent; /* just used for searching */
4940Sstevel@tonic-gate struct node searcheventnode;
4950Sstevel@tonic-gate struct node searchenamenode;
4960Sstevel@tonic-gate
4970Sstevel@tonic-gate searchevent.enode = &searcheventnode;
4980Sstevel@tonic-gate searcheventnode.t = T_EVENT;
4990Sstevel@tonic-gate searcheventnode.u.event.ename = &searchenamenode;
5000Sstevel@tonic-gate searchenamenode.t = T_NAME;
5010Sstevel@tonic-gate searchenamenode.u.name.s = ename;
5020Sstevel@tonic-gate searchevent.ipp = ipp;
5030Sstevel@tonic-gate return (lut_lookup(itp, (void *)&searchevent, (lut_cmp)event_cmp));
5040Sstevel@tonic-gate }
5050Sstevel@tonic-gate
5060Sstevel@tonic-gate static struct event *
find_or_add_event(struct info * infop,struct node * np)5070Sstevel@tonic-gate find_or_add_event(struct info *infop, struct node *np)
5080Sstevel@tonic-gate {
5090Sstevel@tonic-gate struct event *ret;
5100Sstevel@tonic-gate struct event searchevent; /* just used for searching */
5110Sstevel@tonic-gate
5120Sstevel@tonic-gate ASSERTeq(np->t, T_EVENT, ptree_nodetype2str);
5130Sstevel@tonic-gate
5140Sstevel@tonic-gate searchevent.enode = np;
5150Sstevel@tonic-gate searchevent.ipp = ipath(np->u.event.epname);
5160Sstevel@tonic-gate if ((ret = lut_lookup(infop->lut, (void *)&searchevent,
5170Sstevel@tonic-gate (lut_cmp)event_cmp)) != NULL)
5180Sstevel@tonic-gate return (ret);
5190Sstevel@tonic-gate
5200Sstevel@tonic-gate /* wasn't already in tree, allocate it */
5214436Sstephh ret = alloc_xmalloc(sizeof (*ret));
5220Sstevel@tonic-gate bzero(ret, sizeof (*ret));
5230Sstevel@tonic-gate
5240Sstevel@tonic-gate ret->t = np->u.event.ename->u.name.t;
5250Sstevel@tonic-gate ret->enode = np;
5260Sstevel@tonic-gate ret->ipp = searchevent.ipp;
5270Sstevel@tonic-gate ret->props = props2instance(np, np->u.event.epname);
5280Sstevel@tonic-gate
5290Sstevel@tonic-gate infop->lut = lut_add(infop->lut, (void *)ret, (void *)ret,
5300Sstevel@tonic-gate (lut_cmp)event_cmp);
5310Sstevel@tonic-gate
5320Sstevel@tonic-gate return (ret);
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate /*
536*10146SStephen.Hanson@Sun.COM * Used for handling expansions where first part of oldepname is a horizontal
537*10146SStephen.Hanson@Sun.COM * expansion. Recurses through entire tree. oldepname argument is always the
538*10146SStephen.Hanson@Sun.COM * full path as in the rules. Once we find a match we go back to using
539*10146SStephen.Hanson@Sun.COM * hmatch_event to handle the rest.
540*10146SStephen.Hanson@Sun.COM */
541*10146SStephen.Hanson@Sun.COM static void
hmatch_full_config(struct info * infop,struct node * eventnp,struct node * oldepname,struct config * ncp,struct node * nextnp,struct iterinfo * iterinfop)542*10146SStephen.Hanson@Sun.COM hmatch_full_config(struct info *infop, struct node *eventnp,
543*10146SStephen.Hanson@Sun.COM struct node *oldepname, struct config *ncp, struct node *nextnp,
544*10146SStephen.Hanson@Sun.COM struct iterinfo *iterinfop)
545*10146SStephen.Hanson@Sun.COM {
546*10146SStephen.Hanson@Sun.COM char *cp_s;
547*10146SStephen.Hanson@Sun.COM int cp_num;
548*10146SStephen.Hanson@Sun.COM struct config *cp;
549*10146SStephen.Hanson@Sun.COM struct node *saved_ewname;
550*10146SStephen.Hanson@Sun.COM struct node *saved_epname;
551*10146SStephen.Hanson@Sun.COM struct config *pcp, *ocp;
552*10146SStephen.Hanson@Sun.COM struct node *cpnode;
553*10146SStephen.Hanson@Sun.COM struct node *ewlp, *ewfp;
554*10146SStephen.Hanson@Sun.COM
555*10146SStephen.Hanson@Sun.COM for (cp = ncp; cp; cp = config_next(cp)) {
556*10146SStephen.Hanson@Sun.COM config_getcompname(cp, &cp_s, &cp_num);
557*10146SStephen.Hanson@Sun.COM if (cp_s == oldepname->u.name.s) {
558*10146SStephen.Hanson@Sun.COM /*
559*10146SStephen.Hanson@Sun.COM * Found one.
560*10146SStephen.Hanson@Sun.COM */
561*10146SStephen.Hanson@Sun.COM iterinfop->num = cp_num;
562*10146SStephen.Hanson@Sun.COM
563*10146SStephen.Hanson@Sun.COM /*
564*10146SStephen.Hanson@Sun.COM * Need to set ewname, epname for correct node as is
565*10146SStephen.Hanson@Sun.COM * needed by constraint path matching. This code is
566*10146SStephen.Hanson@Sun.COM * similar to that in vmatch_event.
567*10146SStephen.Hanson@Sun.COM */
568*10146SStephen.Hanson@Sun.COM saved_ewname = eventnp->u.event.ewname;
569*10146SStephen.Hanson@Sun.COM saved_epname = eventnp->u.event.epname;
570*10146SStephen.Hanson@Sun.COM ocp = oldepname->u.name.cp;
571*10146SStephen.Hanson@Sun.COM
572*10146SStephen.Hanson@Sun.COM /*
573*10146SStephen.Hanson@Sun.COM * Find correct ewname by walking back up the config
574*10146SStephen.Hanson@Sun.COM * tree adding each name portion as we go.
575*10146SStephen.Hanson@Sun.COM */
576*10146SStephen.Hanson@Sun.COM pcp = config_parent(cp);
577*10146SStephen.Hanson@Sun.COM eventnp->u.event.ewname = NULL;
578*10146SStephen.Hanson@Sun.COM for (; pcp != infop->croot; pcp = config_parent(pcp)) {
579*10146SStephen.Hanson@Sun.COM config_getcompname(pcp, &cp_s, &cp_num);
580*10146SStephen.Hanson@Sun.COM cpnode = tree_name(cp_s, IT_NONE, NULL, 0);
581*10146SStephen.Hanson@Sun.COM cpnode->u.name.child = newnode(T_NUM, NULL, 0);
582*10146SStephen.Hanson@Sun.COM cpnode->u.name.child->u.ull = cp_num;
583*10146SStephen.Hanson@Sun.COM cpnode->u.name.cp = pcp;
584*10146SStephen.Hanson@Sun.COM if (eventnp->u.event.ewname != NULL) {
585*10146SStephen.Hanson@Sun.COM cpnode->u.name.next =
586*10146SStephen.Hanson@Sun.COM eventnp->u.event.ewname;
587*10146SStephen.Hanson@Sun.COM cpnode->u.name.last =
588*10146SStephen.Hanson@Sun.COM eventnp->u.event.ewname->
589*10146SStephen.Hanson@Sun.COM u.name.last;
590*10146SStephen.Hanson@Sun.COM }
591*10146SStephen.Hanson@Sun.COM eventnp->u.event.ewname = cpnode;
592*10146SStephen.Hanson@Sun.COM }
593*10146SStephen.Hanson@Sun.COM
594*10146SStephen.Hanson@Sun.COM /*
595*10146SStephen.Hanson@Sun.COM * Now create correct epname by duping new ewname
596*10146SStephen.Hanson@Sun.COM * and appending oldepname.
597*10146SStephen.Hanson@Sun.COM */
598*10146SStephen.Hanson@Sun.COM ewfp = tname_dup(eventnp->u.event.ewname, CN_DUP);
599*10146SStephen.Hanson@Sun.COM ewlp = ewfp->u.name.last;
600*10146SStephen.Hanson@Sun.COM ewfp->u.name.last = oldepname->u.name.last;
601*10146SStephen.Hanson@Sun.COM ewlp->u.name.next = oldepname;
602*10146SStephen.Hanson@Sun.COM oldepname->u.name.cp = cp;
603*10146SStephen.Hanson@Sun.COM eventnp->u.event.epname = ewfp;
604*10146SStephen.Hanson@Sun.COM
605*10146SStephen.Hanson@Sun.COM outfl(O_ALTFP|O_VERB3|O_NONL, infop->anp->file,
606*10146SStephen.Hanson@Sun.COM infop->anp->line, "hmatch_full_config: ");
607*10146SStephen.Hanson@Sun.COM ptree_name_iter(O_ALTFP|O_VERB3|O_NONL,
608*10146SStephen.Hanson@Sun.COM eventnp->u.event.epname);
609*10146SStephen.Hanson@Sun.COM out(O_ALTFP|O_VERB3, NULL);
610*10146SStephen.Hanson@Sun.COM
611*10146SStephen.Hanson@Sun.COM /*
612*10146SStephen.Hanson@Sun.COM * Now complete hmatch.
613*10146SStephen.Hanson@Sun.COM */
614*10146SStephen.Hanson@Sun.COM hmatch_event(infop, eventnp, oldepname->u.name.next,
615*10146SStephen.Hanson@Sun.COM config_child(cp), nextnp, 1);
616*10146SStephen.Hanson@Sun.COM
617*10146SStephen.Hanson@Sun.COM /*
618*10146SStephen.Hanson@Sun.COM * set everything back again
619*10146SStephen.Hanson@Sun.COM */
620*10146SStephen.Hanson@Sun.COM oldepname->u.name.cp = ocp;
621*10146SStephen.Hanson@Sun.COM iterinfop->num = -1;
622*10146SStephen.Hanson@Sun.COM ewlp->u.name.next = NULL;
623*10146SStephen.Hanson@Sun.COM ewfp->u.name.last = ewlp;
624*10146SStephen.Hanson@Sun.COM tree_free(ewfp);
625*10146SStephen.Hanson@Sun.COM tree_free(eventnp->u.event.ewname);
626*10146SStephen.Hanson@Sun.COM eventnp->u.event.ewname = saved_ewname;
627*10146SStephen.Hanson@Sun.COM eventnp->u.event.epname = saved_epname;
628*10146SStephen.Hanson@Sun.COM }
629*10146SStephen.Hanson@Sun.COM /*
630*10146SStephen.Hanson@Sun.COM * Try the next level down.
631*10146SStephen.Hanson@Sun.COM */
632*10146SStephen.Hanson@Sun.COM hmatch_full_config(infop, eventnp,
633*10146SStephen.Hanson@Sun.COM oldepname, config_child(cp), nextnp, iterinfop);
634*10146SStephen.Hanson@Sun.COM }
635*10146SStephen.Hanson@Sun.COM }
636*10146SStephen.Hanson@Sun.COM
637*10146SStephen.Hanson@Sun.COM /*
6380Sstevel@tonic-gate * hmatch_event -- perform any appropriate horizontal expansion on an event
6390Sstevel@tonic-gate *
6400Sstevel@tonic-gate * this routine is used to perform horizontal expansion on both the
6410Sstevel@tonic-gate * left-hand-side events in a prop, and the right-hand-side events.
6420Sstevel@tonic-gate * when called to handle a left-side event, nextnp point to the right
6430Sstevel@tonic-gate * side of the prop that should be passed to hmatch() for each match
6440Sstevel@tonic-gate * found by horizontal expansion. when no horizontal expansion exists,
6450Sstevel@tonic-gate * we will still "match" one event for every event found in the list on
6460Sstevel@tonic-gate * the left-hand-side of the prop because vmatch() already found that
6470Sstevel@tonic-gate * there's at least one match during vertical expansion.
6480Sstevel@tonic-gate */
6490Sstevel@tonic-gate static void
hmatch_event(struct info * infop,struct node * eventnp,struct node * epname,struct config * ncp,struct node * nextnp,int rematch)6500Sstevel@tonic-gate hmatch_event(struct info *infop, struct node *eventnp, struct node *epname,
6510Sstevel@tonic-gate struct config *ncp, struct node *nextnp, int rematch)
6520Sstevel@tonic-gate {
6530Sstevel@tonic-gate if (epname == NULL) {
6540Sstevel@tonic-gate /*
6550Sstevel@tonic-gate * end of pathname recursion, either we just located
6560Sstevel@tonic-gate * a left-hand-side event and we're ready to move on
6570Sstevel@tonic-gate * to the expanding the right-hand-side events, or
6580Sstevel@tonic-gate * we're further down the recursion and we just located
6590Sstevel@tonic-gate * a right-hand-side event. the passed-in parameter
6600Sstevel@tonic-gate * "nextnp" tells us whether we're working on the left
6610Sstevel@tonic-gate * side and need to move on to nextnp, or if nextnp is
6620Sstevel@tonic-gate * NULL, we're working on the right side.
6630Sstevel@tonic-gate */
6640Sstevel@tonic-gate if (nextnp) {
6650Sstevel@tonic-gate /*
6660Sstevel@tonic-gate * finished a left side expansion, move on to right.
6670Sstevel@tonic-gate * tell generate() what event we just matched so
6680Sstevel@tonic-gate * it can be used at the source of any arrows
6690Sstevel@tonic-gate * we generate as we match events on the right side.
6700Sstevel@tonic-gate */
6714436Sstephh generate_from(eventnp);
6720Sstevel@tonic-gate hmatch(infop, nextnp, NULL);
6730Sstevel@tonic-gate } else {
6740Sstevel@tonic-gate /*
6750Sstevel@tonic-gate * finished a right side expansion. tell generate
6760Sstevel@tonic-gate * the information about the destination and let
6770Sstevel@tonic-gate * it construct the arrows as appropriate.
6780Sstevel@tonic-gate */
6794436Sstephh generate_to(eventnp);
6804436Sstephh generate(infop);
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate
6830Sstevel@tonic-gate return;
6840Sstevel@tonic-gate }
6850Sstevel@tonic-gate
6860Sstevel@tonic-gate ASSERTeq(epname->t, T_NAME, ptree_nodetype2str);
6870Sstevel@tonic-gate
6887197Sstephh if (epname->u.name.cp == NULL)
6897197Sstephh return;
6907197Sstephh
6910Sstevel@tonic-gate /*
6920Sstevel@tonic-gate * we only get here when eventnp already has a completely
6930Sstevel@tonic-gate * instanced epname in it already. so we first recurse
6940Sstevel@tonic-gate * down to the end of the name and as the recursion pops
6950Sstevel@tonic-gate * up, we look for opportunities to advance horizontal
6964436Sstephh * expansions on to the next match.
6970Sstevel@tonic-gate */
6984436Sstephh if (epname->u.name.it == IT_HORIZONTAL || rematch) {
6990Sstevel@tonic-gate struct config *cp;
7000Sstevel@tonic-gate struct config *ocp = epname->u.name.cp;
7010Sstevel@tonic-gate char *cp_s;
7020Sstevel@tonic-gate int cp_num;
7030Sstevel@tonic-gate int ocp_num;
7040Sstevel@tonic-gate struct iterinfo *iterinfop = NULL;
7050Sstevel@tonic-gate const char *iters;
7064436Sstephh int hexpand = 0;
7070Sstevel@tonic-gate
7084436Sstephh if (epname->u.name.it != IT_HORIZONTAL) {
7094436Sstephh /*
7104436Sstephh * Ancestor was horizontal though, so must rematch
7114436Sstephh * against the name/num found in vmatch.
7124436Sstephh */
7134436Sstephh config_getcompname(ocp, NULL, &ocp_num);
7144436Sstephh } else {
7154436Sstephh iters = epname->u.name.child->u.name.s;
7164436Sstephh if ((iterinfop = lut_lookup(infop->ex,
7174436Sstephh (void *)iters, NULL)) == NULL) {
7184436Sstephh /*
7194436Sstephh * do horizontal expansion on this node
7204436Sstephh */
7214436Sstephh hexpand = 1;
7224436Sstephh iterinfop = alloc_xmalloc(
7234436Sstephh sizeof (struct iterinfo));
7244436Sstephh iterinfop->num = -1;
7254436Sstephh iterinfop->np = epname;
7264436Sstephh infop->ex = lut_add(infop->ex, (void *)iters,
7274436Sstephh iterinfop, NULL);
7284436Sstephh } else if (iterinfop->num == -1) {
7294436Sstephh hexpand = 1;
7304436Sstephh } else {
7314436Sstephh /*
7324436Sstephh * This name has already been used in a
7334436Sstephh * horizontal expansion. This time just match it
7344436Sstephh */
7354436Sstephh ocp_num = iterinfop->num;
7364436Sstephh }
7374436Sstephh }
7384436Sstephh /*
739*10146SStephen.Hanson@Sun.COM * handle case where this is the first section of oldepname
740*10146SStephen.Hanson@Sun.COM * and it is horizontally expanded. Instead of just looking for
741*10146SStephen.Hanson@Sun.COM * siblings, we want to scan the entire config tree for further
742*10146SStephen.Hanson@Sun.COM * matches.
743*10146SStephen.Hanson@Sun.COM */
744*10146SStephen.Hanson@Sun.COM if (epname == eventnp->u.event.oldepname &&
745*10146SStephen.Hanson@Sun.COM epname->u.name.it == IT_HORIZONTAL) {
746*10146SStephen.Hanson@Sun.COM /*
747*10146SStephen.Hanson@Sun.COM * Run through config looking for any that match the
748*10146SStephen.Hanson@Sun.COM * name.
749*10146SStephen.Hanson@Sun.COM */
750*10146SStephen.Hanson@Sun.COM hmatch_full_config(infop, eventnp, epname,
751*10146SStephen.Hanson@Sun.COM infop->croot, nextnp, iterinfop);
752*10146SStephen.Hanson@Sun.COM return;
753*10146SStephen.Hanson@Sun.COM }
754*10146SStephen.Hanson@Sun.COM
755*10146SStephen.Hanson@Sun.COM /*
7564436Sstephh * Run through siblings looking for any that match the name.
7574436Sstephh * If hexpand not set then num must also match ocp_num.
7584436Sstephh */
7594436Sstephh for (cp = rematch ? ncp : ocp; cp; cp = config_next(cp)) {
7604436Sstephh config_getcompname(cp, &cp_s, &cp_num);
7614436Sstephh if (cp_s == epname->u.name.s) {
7624436Sstephh if (hexpand)
7630Sstevel@tonic-gate iterinfop->num = cp_num;
7644436Sstephh else if (ocp_num != cp_num)
7654436Sstephh continue;
7660Sstevel@tonic-gate epname->u.name.cp = cp;
7670Sstevel@tonic-gate hmatch_event(infop, eventnp,
7680Sstevel@tonic-gate epname->u.name.next, config_child(cp),
7690Sstevel@tonic-gate nextnp, 1);
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate epname->u.name.cp = ocp;
7734436Sstephh if (hexpand)
7744436Sstephh iterinfop->num = -1;
7754436Sstephh } else {
7764436Sstephh hmatch_event(infop, eventnp, epname->u.name.next,
7774436Sstephh NULL, nextnp, 0);
7780Sstevel@tonic-gate }
7790Sstevel@tonic-gate }
7800Sstevel@tonic-gate
7810Sstevel@tonic-gate /*
7820Sstevel@tonic-gate * hmatch -- check for horizontal expansion matches
7830Sstevel@tonic-gate *
7840Sstevel@tonic-gate * np points to the things we're matching (like a T_LIST or a T_EVENT)
7850Sstevel@tonic-gate * and if we're working on a left-side of a prop, nextnp points to
7860Sstevel@tonic-gate * the other side of the prop that we'll tackle next when this recursion
7870Sstevel@tonic-gate * bottoms out. when all the events in the entire prop arrow have been
7880Sstevel@tonic-gate * horizontally expanded, generate() will be called to generate the
7890Sstevel@tonic-gate * actualy arrow.
7900Sstevel@tonic-gate */
7910Sstevel@tonic-gate static void
hmatch(struct info * infop,struct node * np,struct node * nextnp)7920Sstevel@tonic-gate hmatch(struct info *infop, struct node *np, struct node *nextnp)
7930Sstevel@tonic-gate {
7940Sstevel@tonic-gate if (np == NULL)
7950Sstevel@tonic-gate return; /* all done */
7960Sstevel@tonic-gate
7970Sstevel@tonic-gate /*
7980Sstevel@tonic-gate * for each item in the list of events (which could just
7990Sstevel@tonic-gate * be a single event, or it could get larger in the loop
8000Sstevel@tonic-gate * below due to horizontal expansion), call hmatch on
8010Sstevel@tonic-gate * the right side and create arrows to each element.
8020Sstevel@tonic-gate */
8030Sstevel@tonic-gate
8040Sstevel@tonic-gate switch (np->t) {
8050Sstevel@tonic-gate case T_LIST:
8060Sstevel@tonic-gate /* loop through the list */
8070Sstevel@tonic-gate if (np->u.expr.left)
8080Sstevel@tonic-gate hmatch(infop, np->u.expr.left, nextnp);
8090Sstevel@tonic-gate if (np->u.expr.right)
8100Sstevel@tonic-gate hmatch(infop, np->u.expr.right, nextnp);
8110Sstevel@tonic-gate break;
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate case T_EVENT:
8140Sstevel@tonic-gate hmatch_event(infop, np, np->u.event.epname,
8150Sstevel@tonic-gate NULL, nextnp, 0);
8160Sstevel@tonic-gate break;
8170Sstevel@tonic-gate
8180Sstevel@tonic-gate default:
8190Sstevel@tonic-gate outfl(O_DIE, np->file, np->line,
8200Sstevel@tonic-gate "hmatch: unexpected type: %s",
8210Sstevel@tonic-gate ptree_nodetype2str(np->t));
8220Sstevel@tonic-gate }
8230Sstevel@tonic-gate }
8240Sstevel@tonic-gate
8250Sstevel@tonic-gate static int
itree_np2nork(struct node * norknp)8260Sstevel@tonic-gate itree_np2nork(struct node *norknp)
8270Sstevel@tonic-gate {
8280Sstevel@tonic-gate if (norknp == NULL)
8290Sstevel@tonic-gate return (1);
8300Sstevel@tonic-gate else if (norknp->t == T_NAME && norknp->u.name.s == L_A)
8310Sstevel@tonic-gate return (-1); /* our internal version of "all" */
8320Sstevel@tonic-gate else if (norknp->t == T_NUM)
8330Sstevel@tonic-gate return ((int)norknp->u.ull);
8340Sstevel@tonic-gate else
8354436Sstephh outfl(O_DIE, norknp->file, norknp->line,
8360Sstevel@tonic-gate "itree_np2nork: internal error type %s",
8370Sstevel@tonic-gate ptree_nodetype2str(norknp->t));
8380Sstevel@tonic-gate /*NOTREACHED*/
8391717Swesolows return (1);
8400Sstevel@tonic-gate }
8410Sstevel@tonic-gate
8420Sstevel@tonic-gate static struct iterinfo *
newiterinfo(int num,struct node * np)8430Sstevel@tonic-gate newiterinfo(int num, struct node *np)
8440Sstevel@tonic-gate {
8454436Sstephh struct iterinfo *ret = alloc_xmalloc(sizeof (*ret));
8460Sstevel@tonic-gate
8470Sstevel@tonic-gate ret->num = num;
8480Sstevel@tonic-gate ret->np = np;
8490Sstevel@tonic-gate return (ret);
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate
8520Sstevel@tonic-gate /*ARGSUSED*/
8530Sstevel@tonic-gate static void
iterinfo_destructor(void * left,void * right,void * arg)8540Sstevel@tonic-gate iterinfo_destructor(void *left, void *right, void *arg)
8550Sstevel@tonic-gate {
8560Sstevel@tonic-gate struct iterinfo *iterinfop = (struct iterinfo *)right;
8570Sstevel@tonic-gate
8584436Sstephh alloc_xfree(iterinfop, sizeof (*iterinfop));
8590Sstevel@tonic-gate }
8600Sstevel@tonic-gate
8614436Sstephh static void
vmatch_event(struct info * infop,struct config * cp,struct node * np,struct node * lnp,struct node * anp,struct wildcardinfo * wcp)8624436Sstephh vmatch_event(struct info *infop, struct config *cp, struct node *np,
8634436Sstephh struct node *lnp, struct node *anp, struct wildcardinfo *wcp)
864186Sdb35262 {
8654436Sstephh char *cp_s;
8664436Sstephh int cp_num;
8674436Sstephh struct node *ewlp, *ewfp;
8684436Sstephh struct config *pcp;
8694436Sstephh struct node *cpnode;
8704436Sstephh int newewname = 0;
871186Sdb35262
872*10146SStephen.Hanson@Sun.COM /*
873*10146SStephen.Hanson@Sun.COM * handle case where the first section of the path name is horizontally
874*10146SStephen.Hanson@Sun.COM * expanded. The whole expansion is handled by hmatch on the first
875*10146SStephen.Hanson@Sun.COM * match here - so we just skip any subsequent matches here.
876*10146SStephen.Hanson@Sun.COM */
877*10146SStephen.Hanson@Sun.COM if (wcp->got_wc_hz == 1)
878*10146SStephen.Hanson@Sun.COM return;
879*10146SStephen.Hanson@Sun.COM
8804436Sstephh if (np == NULL) {
881186Sdb35262 /*
8824436Sstephh * Reached the end of the name. u.name.cp pointers should be set
8834436Sstephh * up for each part of name. From this we can use config tree
8844436Sstephh * to build up the wildcard part of the name (if any).
885186Sdb35262 */
8864436Sstephh pcp = config_parent(wcp->nptop->u.event.epname->u.name.cp);
8874436Sstephh if (pcp == infop->croot) {
8884436Sstephh /*
8894436Sstephh * no wildcarding done - move on to next entry
8904436Sstephh */
8914436Sstephh wcp->nptop->u.event.ewname = wcp->ewname;
8924436Sstephh wcp->nptop->u.event.oldepname = wcp->oldepname;
8934436Sstephh vmatch(infop, np, lnp, anp);
894*10146SStephen.Hanson@Sun.COM wcp->got_wc_hz = 0;
8954436Sstephh return;
8964436Sstephh }
8974436Sstephh if (wcp->ewname == NULL) {
8984436Sstephh /*
8994436Sstephh * ewname not yet set up - do it now
9004436Sstephh */
9014436Sstephh newewname = 1;
9024436Sstephh for (; pcp != infop->croot; pcp = config_parent(pcp)) {
9034436Sstephh config_getcompname(pcp, &cp_s, &cp_num);
9044436Sstephh cpnode = tree_name(cp_s, IT_NONE, NULL, 0);
9054436Sstephh cpnode->u.name.child = newnode(T_NUM, NULL, 0);
9064436Sstephh cpnode->u.name.child->u.ull = cp_num;
9074436Sstephh cpnode->u.name.cp = pcp;
9084436Sstephh if (wcp->ewname != NULL) {
9094436Sstephh cpnode->u.name.next = wcp->ewname;
9104436Sstephh cpnode->u.name.last =
9114436Sstephh wcp->ewname->u.name.last;
9124436Sstephh }
9134436Sstephh wcp->ewname = cpnode;
9144436Sstephh }
9154436Sstephh }
916186Sdb35262
917186Sdb35262 /*
9184436Sstephh * dup ewname and append oldepname
919186Sdb35262 */
9204436Sstephh ewfp = tname_dup(wcp->ewname, CN_DUP);
9214436Sstephh ewlp = ewfp->u.name.last;
9224436Sstephh ewfp->u.name.last = wcp->oldepname->u.name.last;
9234436Sstephh ewlp->u.name.next = wcp->oldepname;
9244436Sstephh
9254436Sstephh wcp->nptop->u.event.epname = ewfp;
9264436Sstephh wcp->nptop->u.event.ewname = wcp->ewname;
9274436Sstephh wcp->nptop->u.event.oldepname = wcp->oldepname;
9284436Sstephh vmatch(infop, np, lnp, anp);
929*10146SStephen.Hanson@Sun.COM wcp->got_wc_hz = 0;
9304436Sstephh wcp->nptop->u.event.epname = wcp->oldepname;
931186Sdb35262
9324436Sstephh /*
9334436Sstephh * reduce duped ewname to original then free
9344436Sstephh */
9354436Sstephh ewlp->u.name.next = NULL;
9364436Sstephh ewfp->u.name.last = ewlp;
9374436Sstephh tree_free(ewfp);
938186Sdb35262
9394436Sstephh if (newewname) {
9404436Sstephh /*
9414436Sstephh * free ewname if allocated above
9424436Sstephh */
9434436Sstephh tree_free(wcp->ewname);
9444436Sstephh wcp->ewname = NULL;
9454436Sstephh }
9464436Sstephh return;
947186Sdb35262 }
948186Sdb35262
949186Sdb35262 /*
9504436Sstephh * We have an np. See if we can match it in this section of
9514436Sstephh * the config tree.
9520Sstevel@tonic-gate */
9530Sstevel@tonic-gate if (cp == NULL)
9540Sstevel@tonic-gate return; /* no more config to match against */
9550Sstevel@tonic-gate
9560Sstevel@tonic-gate for (; cp; cp = config_next(cp)) {
9570Sstevel@tonic-gate config_getcompname(cp, &cp_s, &cp_num);
9580Sstevel@tonic-gate
9594436Sstephh if (cp_s == np->u.name.s) {
9600Sstevel@tonic-gate /* found a matching component name */
9610Sstevel@tonic-gate if (np->u.name.child &&
9620Sstevel@tonic-gate np->u.name.child->t == T_NUM) {
9630Sstevel@tonic-gate /*
9640Sstevel@tonic-gate * an explicit instance number was given
9650Sstevel@tonic-gate * in the source. so only consider this
9660Sstevel@tonic-gate * a configuration match if the number
9670Sstevel@tonic-gate * also matches.
9680Sstevel@tonic-gate */
9690Sstevel@tonic-gate if (cp_num != np->u.name.child->u.ull)
9700Sstevel@tonic-gate continue;
9710Sstevel@tonic-gate
9724436Sstephh } else if (np->u.name.it != IT_HORIZONTAL) {
9730Sstevel@tonic-gate struct iterinfo *iterinfop;
9740Sstevel@tonic-gate const char *iters;
9750Sstevel@tonic-gate
9760Sstevel@tonic-gate /*
9770Sstevel@tonic-gate * vertical iterator. look it up in
9780Sstevel@tonic-gate * the appropriate lut and if we get
9790Sstevel@tonic-gate * back a value it is either one that we
9800Sstevel@tonic-gate * set earlier, in which case we record
9810Sstevel@tonic-gate * the new value for this iteration and
9820Sstevel@tonic-gate * keep matching, or it is one that was
9830Sstevel@tonic-gate * set by an earlier reference to the
9840Sstevel@tonic-gate * iterator, in which case we only consider
9850Sstevel@tonic-gate * this a configuration match if the number
9860Sstevel@tonic-gate * matches cp_num.
9870Sstevel@tonic-gate */
9880Sstevel@tonic-gate
9890Sstevel@tonic-gate ASSERT(np->u.name.child != NULL);
9900Sstevel@tonic-gate ASSERT(np->u.name.child->t == T_NAME);
9910Sstevel@tonic-gate iters = np->u.name.child->u.name.s;
9920Sstevel@tonic-gate
9930Sstevel@tonic-gate if ((iterinfop = lut_lookup(infop->ex,
9940Sstevel@tonic-gate (void *)iters, NULL)) == NULL) {
9950Sstevel@tonic-gate /* we're the first use, record our np */
9960Sstevel@tonic-gate infop->ex = lut_add(infop->ex,
9970Sstevel@tonic-gate (void *)iters,
9980Sstevel@tonic-gate newiterinfo(cp_num, np), NULL);
9990Sstevel@tonic-gate } else if (np == iterinfop->np) {
10000Sstevel@tonic-gate /*
10010Sstevel@tonic-gate * we're the first use, back again
10020Sstevel@tonic-gate * for another iteration. so update
10030Sstevel@tonic-gate * the num bound to this iterator in
10040Sstevel@tonic-gate * the lut.
10050Sstevel@tonic-gate */
10060Sstevel@tonic-gate iterinfop->num = cp_num;
10070Sstevel@tonic-gate } else if (cp_num != iterinfop->num) {
10080Sstevel@tonic-gate /*
10090Sstevel@tonic-gate * an earlier reference to this
10100Sstevel@tonic-gate * iterator bound it to a different
10110Sstevel@tonic-gate * instance number, so there's no
10120Sstevel@tonic-gate * match here after all.
1013186Sdb35262 *
1014186Sdb35262 * however, it's possible that this
1015186Sdb35262 * component should really be part of
1016186Sdb35262 * the wildcard. we explore this by
1017186Sdb35262 * forcing this component into the
1018186Sdb35262 * wildcarded section.
1019186Sdb35262 *
1020186Sdb35262 * for an more details of what's
1021186Sdb35262 * going to happen now, see
1022186Sdb35262 * comments block below entitled
1023186Sdb35262 * "forcing components into
1024186Sdb35262 * wildcard path".
10250Sstevel@tonic-gate */
10264436Sstephh if (np == wcp->nptop->u.event.epname)
10274436Sstephh vmatch_event(infop,
10284436Sstephh config_child(cp), np, lnp,
10294436Sstephh anp, wcp);
10300Sstevel@tonic-gate continue;
10310Sstevel@tonic-gate }
10320Sstevel@tonic-gate }
10330Sstevel@tonic-gate
10340Sstevel@tonic-gate /*
10354436Sstephh * if this was an IT_HORIZONTAL name, hmatch() will
10364436Sstephh * expand all matches horizontally into a list.
10370Sstevel@tonic-gate * we know the list will contain at least
10380Sstevel@tonic-gate * one element (the one we just matched),
10394436Sstephh * so we just let hmatch_event() do the rest.
10400Sstevel@tonic-gate *
10414436Sstephh * recurse on to next component. Note that
10420Sstevel@tonic-gate * wildcarding is now turned off.
10430Sstevel@tonic-gate */
10444436Sstephh np->u.name.cp = cp;
10450Sstevel@tonic-gate vmatch_event(infop, config_child(cp), np->u.name.next,
10464436Sstephh lnp, anp, wcp);
10474436Sstephh np->u.name.cp = NULL;
10480Sstevel@tonic-gate
10490Sstevel@tonic-gate /*
1050*10146SStephen.Hanson@Sun.COM * handle case where this is the first section of the
1051*10146SStephen.Hanson@Sun.COM * path name and it is horizontally expanded.
1052*10146SStephen.Hanson@Sun.COM * In this case we want all matching nodes in the config
1053*10146SStephen.Hanson@Sun.COM * to be expanded horizontally - so set got_wc_hz and
1054*10146SStephen.Hanson@Sun.COM * leave all further processing to hmatch.
1055*10146SStephen.Hanson@Sun.COM */
1056*10146SStephen.Hanson@Sun.COM if (G.matched && np == wcp->nptop->u.event.epname &&
1057*10146SStephen.Hanson@Sun.COM np->u.name.it == IT_HORIZONTAL)
1058*10146SStephen.Hanson@Sun.COM wcp->got_wc_hz = 1;
1059*10146SStephen.Hanson@Sun.COM
1060*10146SStephen.Hanson@Sun.COM /*
1061186Sdb35262 * forcing components into wildcard path:
1062186Sdb35262 *
1063186Sdb35262 * if this component is the first match, force it
1064186Sdb35262 * to be part of the wildcarded path and see if we
10654436Sstephh * can get additional matches.
1066186Sdb35262 *
1067186Sdb35262 * here's an example. suppose we have the
1068186Sdb35262 * definition
1069186Sdb35262 * event foo@x/y
1070186Sdb35262 * and configuration
1071186Sdb35262 * a0/x0/y0/a1/x1/y1
1072186Sdb35262 *
1073186Sdb35262 * the code up to this point will treat "a0" as the
1074186Sdb35262 * wildcarded part of the path and "x0/y0" as the
1075186Sdb35262 * nonwildcarded part, resulting in the instanced
1076186Sdb35262 * event
1077186Sdb35262 * foo@a0/x0/y0
1078186Sdb35262 *
1079186Sdb35262 * in order to discover the next match (.../x1/y1)
1080186Sdb35262 * in the configuration we have to force "x0" into
10814436Sstephh * the wildcarded part of the path.
1082186Sdb35262 * by doing so, we discover the wildcarded part
1083186Sdb35262 * "a0/x0/y0/a1" and the nonwildcarded part "x1/y1"
1084186Sdb35262 *
1085186Sdb35262 * the following call to vmatch_event() is also
1086186Sdb35262 * needed to properly handle the configuration
1087186Sdb35262 * b0/x0/b1/x1/y1
1088186Sdb35262 *
1089186Sdb35262 * the recursions into vmatch_event() will start
1090186Sdb35262 * off uncovering "b0" as the wildcarded part and
1091186Sdb35262 * "x0" as the start of the nonwildcarded path.
1092186Sdb35262 * however, the next recursion will not result in a
1093186Sdb35262 * match since there is no "y" following "x0". the
1094186Sdb35262 * subsequent match of (wildcard = "b0/x0/b1" and
1095186Sdb35262 * nonwildcard = "x1/y1") will be discovered only
1096186Sdb35262 * if "x0" is forced to be a part of the wildcarded
1097186Sdb35262 * path.
10980Sstevel@tonic-gate */
10994436Sstephh if (np == wcp->nptop->u.event.epname)
11004436Sstephh vmatch_event(infop, config_child(cp), np, lnp,
11014436Sstephh anp, wcp);
11020Sstevel@tonic-gate
11030Sstevel@tonic-gate if (np->u.name.it == IT_HORIZONTAL) {
11040Sstevel@tonic-gate /*
11050Sstevel@tonic-gate * hmatch() finished iterating through
11060Sstevel@tonic-gate * the configuration as described above, so
11070Sstevel@tonic-gate * don't continue iterating here.
11080Sstevel@tonic-gate */
11090Sstevel@tonic-gate return;
11100Sstevel@tonic-gate }
11114436Sstephh } else if (np == wcp->nptop->u.event.epname) {
11120Sstevel@tonic-gate /*
11134436Sstephh * no match - carry on down the tree looking for
11144436Sstephh * wildcarding
11150Sstevel@tonic-gate */
11160Sstevel@tonic-gate vmatch_event(infop, config_child(cp), np, lnp, anp,
11174436Sstephh wcp);
11180Sstevel@tonic-gate }
11190Sstevel@tonic-gate }
11200Sstevel@tonic-gate }
11210Sstevel@tonic-gate
11220Sstevel@tonic-gate /*
11230Sstevel@tonic-gate * vmatch -- find the next vertical expansion match in the config database
11240Sstevel@tonic-gate *
11250Sstevel@tonic-gate * this routine is called with three node pointers:
11260Sstevel@tonic-gate * np -- the parse we're matching
11270Sstevel@tonic-gate * lnp -- the rest of the list we're currently working on
11280Sstevel@tonic-gate * anp -- the rest of the arrow we're currently working on
11290Sstevel@tonic-gate *
11300Sstevel@tonic-gate * the expansion matching happens via three types of recursion:
11310Sstevel@tonic-gate *
11320Sstevel@tonic-gate * - when given an arrow, handle the left-side and then recursively
11330Sstevel@tonic-gate * handle the right side (which might be another cascaded arrow).
11340Sstevel@tonic-gate *
11350Sstevel@tonic-gate * - when handling one side of an arrow, recurse through the T_LIST
11360Sstevel@tonic-gate * to get to each event (or just move on to the event if there
11370Sstevel@tonic-gate * is a single event instead of a list) since the arrow parse
11380Sstevel@tonic-gate * trees recurse left, we actually start with the right-most
11390Sstevel@tonic-gate * event list in the prop statement and work our way towards
11400Sstevel@tonic-gate * the left-most event list.
11410Sstevel@tonic-gate *
11420Sstevel@tonic-gate * - when handling an event, recurse down each component of the
11430Sstevel@tonic-gate * pathname, matching in the config database and recording the
11440Sstevel@tonic-gate * matches in the explicit iterator dictionary as we go.
11450Sstevel@tonic-gate *
11460Sstevel@tonic-gate * when the bottom of this matching recursion is met, meaning we have
11470Sstevel@tonic-gate * set the "cp" pointers on all the names in the entire statement,
11480Sstevel@tonic-gate * we call hmatch() which does it's own recursion to handle horizontal
11490Sstevel@tonic-gate * expandsion and then call generate() to generate nodes, bubbles, and
11500Sstevel@tonic-gate * arrows in the instance tree. generate() looks at the cp pointers to
11510Sstevel@tonic-gate * see what instance numbers were matched in the configuration database.
11520Sstevel@tonic-gate *
11530Sstevel@tonic-gate * when horizontal expansion appears, vmatch() finds only the first match
11540Sstevel@tonic-gate * and hmatch() then takes the horizontal expansion through all the other
11550Sstevel@tonic-gate * matches when generating the arrows in the instance tree.
11560Sstevel@tonic-gate *
11570Sstevel@tonic-gate * the "infop" passed down through the recursion contains a dictionary
11580Sstevel@tonic-gate * of the explicit iterators (all the implicit iterators have been converted
11590Sstevel@tonic-gate * to explicit iterators when the parse tree was created by tree.c), which
11600Sstevel@tonic-gate * allows things like this to work correctly:
11610Sstevel@tonic-gate *
11620Sstevel@tonic-gate * prop error.a@x[n]/y/z -> error.b@x/y[n]/z -> error.c@x/y/z[n];
11630Sstevel@tonic-gate *
11640Sstevel@tonic-gate * during the top level call, the explicit iterator "n" will match an
11650Sstevel@tonic-gate * instance number in the config database, and the result will be recorded
11660Sstevel@tonic-gate * in the explicit iterator dictionary and passed down via "infop". so
11670Sstevel@tonic-gate * when the recursive call tries to match y[n] in the config database, it
11680Sstevel@tonic-gate * will only match the same instance number as x[n] did since the dictionary
11690Sstevel@tonic-gate * is consulted to see if "n" took on a value already.
11700Sstevel@tonic-gate *
11710Sstevel@tonic-gate * at any point during the recursion, match*() can return to indicate
11720Sstevel@tonic-gate * a match was not found in the config database and that the caller should
11730Sstevel@tonic-gate * move on to the next potential match, if any.
11740Sstevel@tonic-gate *
11750Sstevel@tonic-gate * constraints are completely ignored by match(), so the statement:
11760Sstevel@tonic-gate *
11770Sstevel@tonic-gate * prop error.a@x[n] -> error.b@x[n] {n != 0};
11780Sstevel@tonic-gate *
11790Sstevel@tonic-gate * might very well match x[0] if it appears in the config database. it
11800Sstevel@tonic-gate * is the generate() routine that takes that match and then decides what
11810Sstevel@tonic-gate * arrow, if any, should be generated in the instance tree. generate()
11820Sstevel@tonic-gate * looks at the explicit iterator dictionary to get values like "n" in
11830Sstevel@tonic-gate * the above example so that it can evaluate constraints.
11840Sstevel@tonic-gate *
11850Sstevel@tonic-gate */
11860Sstevel@tonic-gate static void
vmatch(struct info * infop,struct node * np,struct node * lnp,struct node * anp)11874436Sstephh vmatch(struct info *infop, struct node *np, struct node *lnp, struct node *anp)
11880Sstevel@tonic-gate {
11894436Sstephh struct node *np1, *np2, *oldepname, *oldnptop;
11904436Sstephh int epmatches;
11914436Sstephh struct config *cp;
11924436Sstephh struct wildcardinfo *wcp;
11934436Sstephh
11940Sstevel@tonic-gate if (np == NULL) {
11957197Sstephh G.matched = 1;
11960Sstevel@tonic-gate if (lnp)
11974436Sstephh vmatch(infop, lnp, NULL, anp);
11980Sstevel@tonic-gate else if (anp)
11994436Sstephh vmatch(infop, anp, NULL, NULL);
12000Sstevel@tonic-gate else {
12010Sstevel@tonic-gate struct node *src;
12020Sstevel@tonic-gate struct node *dst;
12030Sstevel@tonic-gate
12040Sstevel@tonic-gate /* end of vertical match recursion */
12050Sstevel@tonic-gate outfl(O_ALTFP|O_VERB3|O_NONL,
12060Sstevel@tonic-gate infop->anp->file, infop->anp->line, "vmatch: ");
12070Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, infop->anp);
12080Sstevel@tonic-gate out(O_ALTFP|O_VERB3, NULL);
12090Sstevel@tonic-gate
12100Sstevel@tonic-gate generate_nork(
12110Sstevel@tonic-gate itree_np2nork(infop->anp->u.arrow.nnp),
12120Sstevel@tonic-gate itree_np2nork(infop->anp->u.arrow.knp));
12130Sstevel@tonic-gate dst = infop->anp->u.arrow.rhs;
12140Sstevel@tonic-gate src = infop->anp->u.arrow.lhs;
12150Sstevel@tonic-gate for (;;) {
12160Sstevel@tonic-gate generate_new(); /* new set of arrows */
12170Sstevel@tonic-gate if (src->t == T_ARROW) {
12180Sstevel@tonic-gate hmatch(infop, src->u.arrow.rhs, dst);
12190Sstevel@tonic-gate generate_nork(
12200Sstevel@tonic-gate itree_np2nork(src->u.arrow.nnp),
12210Sstevel@tonic-gate itree_np2nork(src->u.arrow.knp));
12220Sstevel@tonic-gate dst = src->u.arrow.rhs;
12230Sstevel@tonic-gate src = src->u.arrow.lhs;
12240Sstevel@tonic-gate } else {
12250Sstevel@tonic-gate hmatch(infop, src, dst);
12260Sstevel@tonic-gate break;
12270Sstevel@tonic-gate }
12280Sstevel@tonic-gate }
12290Sstevel@tonic-gate }
12300Sstevel@tonic-gate return;
12310Sstevel@tonic-gate }
12320Sstevel@tonic-gate
12330Sstevel@tonic-gate switch (np->t) {
12340Sstevel@tonic-gate case T_EVENT: {
12354436Sstephh epmatches = 0;
12364436Sstephh /*
12374436Sstephh * see if we already have a match in the wcps
12384436Sstephh */
12394436Sstephh for (wcp = wcproot; wcp; wcp = wcp->next) {
12404436Sstephh oldepname = wcp->oldepname;
12414436Sstephh oldnptop = wcp->nptop;
12424436Sstephh for (np1 = oldepname, np2 = np->u.event.epname;
12434436Sstephh np1 != NULL && np2 != NULL; np1 = np1->u.name.next,
12444436Sstephh np2 = np2->u.name.next) {
12454436Sstephh if (strcmp(np1->u.name.s, np2->u.name.s) != 0)
12464436Sstephh break;
12474436Sstephh if (np1->u.name.child->t !=
12484436Sstephh np2->u.name.child->t)
12494436Sstephh break;
12504436Sstephh if (np1->u.name.child->t == T_NUM &&
12514436Sstephh np1->u.name.child->u.ull !=
12524436Sstephh np2->u.name.child->u.ull)
12534436Sstephh break;
12544436Sstephh if (np1->u.name.child->t == T_NAME &&
12554436Sstephh strcmp(np1->u.name.child->u.name.s,
12564436Sstephh np2->u.name.child->u.name.s) != 0)
12574436Sstephh break;
12584436Sstephh epmatches++;
12594436Sstephh }
12604436Sstephh if (epmatches)
12614436Sstephh break;
12624436Sstephh }
12634436Sstephh if (epmatches && np1 == NULL && np2 == NULL) {
12644436Sstephh /*
12654436Sstephh * complete names match, can just borrow the fields
12664436Sstephh */
12674436Sstephh oldepname = np->u.event.epname;
12684436Sstephh np->u.event.epname = oldnptop->u.event.epname;
12694436Sstephh np->u.event.oldepname = wcp->oldepname;
12704436Sstephh np->u.event.ewname = wcp->ewname;
12714436Sstephh vmatch(infop, NULL, lnp, anp);
12724436Sstephh np->u.event.epname = oldepname;
12734436Sstephh return;
12744436Sstephh }
12757197Sstephh G.matched = 0;
12764436Sstephh if (epmatches) {
12774436Sstephh /*
12784436Sstephh * just first part of names match - do wildcarding
12794436Sstephh * by using existing wcp including ewname and also
12804436Sstephh * copying as much of pwname as is valid, then start
12814436Sstephh * vmatch_event() at start of non-matching section
12824436Sstephh */
12834436Sstephh for (np1 = oldepname, np2 = np->u.event.epname;
12844436Sstephh epmatches != 0; epmatches--) {
12854436Sstephh cp = np1->u.name.cp;
12864436Sstephh np2->u.name.cp = cp;
12874436Sstephh np1 = np1->u.name.next;
12884436Sstephh np2 = np2->u.name.next;
12894436Sstephh }
12904436Sstephh wcp->oldepname = np->u.event.epname;
12914436Sstephh wcp->nptop = np;
12924436Sstephh vmatch_event(infop, config_child(cp), np2, lnp,
12934436Sstephh anp, wcp);
12944436Sstephh wcp->oldepname = oldepname;
12954436Sstephh wcp->nptop = oldnptop;
12967197Sstephh if (G.matched == 0) {
12977197Sstephh /*
12987197Sstephh * This list entry is NULL. Move on to next item
12997197Sstephh * in the list.
13007197Sstephh */
13017197Sstephh vmatch(infop, NULL, lnp, anp);
13027197Sstephh }
13034436Sstephh return;
13044436Sstephh }
13054436Sstephh /*
13064436Sstephh * names do not match - allocate a new wcp
13074436Sstephh */
13084436Sstephh wcp = MALLOC(sizeof (struct wildcardinfo));
13094436Sstephh wcp->next = wcproot;
13104436Sstephh wcproot = wcp;
13114436Sstephh wcp->nptop = np;
13124436Sstephh wcp->oldepname = np->u.event.epname;
13134436Sstephh wcp->ewname = NULL;
1314*10146SStephen.Hanson@Sun.COM wcp->got_wc_hz = 0;
13154436Sstephh
1316186Sdb35262 vmatch_event(infop, config_child(infop->croot),
13174436Sstephh np->u.event.epname, lnp, anp, wcp);
13184436Sstephh
13194436Sstephh wcproot = wcp->next;
13204436Sstephh FREE(wcp);
13217197Sstephh if (G.matched == 0) {
13227197Sstephh /*
13237197Sstephh * This list entry is NULL. Move on to next item in the
13247197Sstephh * list.
13257197Sstephh */
13267197Sstephh vmatch(infop, NULL, lnp, anp);
13277197Sstephh }
13280Sstevel@tonic-gate break;
13290Sstevel@tonic-gate }
13300Sstevel@tonic-gate case T_LIST:
13310Sstevel@tonic-gate ASSERT(lnp == NULL);
13324436Sstephh vmatch(infop, np->u.expr.right, np->u.expr.left, anp);
13330Sstevel@tonic-gate break;
13340Sstevel@tonic-gate
13350Sstevel@tonic-gate case T_ARROW:
13360Sstevel@tonic-gate ASSERT(lnp == NULL && anp == NULL);
13377197Sstephh vmatch(infop, np->u.arrow.rhs, NULL, np->u.arrow.parent);
13380Sstevel@tonic-gate break;
13390Sstevel@tonic-gate
13400Sstevel@tonic-gate default:
13410Sstevel@tonic-gate outfl(O_DIE, np->file, np->line,
13420Sstevel@tonic-gate "vmatch: unexpected type: %s",
13430Sstevel@tonic-gate ptree_nodetype2str(np->t));
13440Sstevel@tonic-gate }
13450Sstevel@tonic-gate }
13460Sstevel@tonic-gate
13470Sstevel@tonic-gate static void
find_first_arrow(struct info * infop,struct node * anp)13487197Sstephh find_first_arrow(struct info *infop, struct node *anp)
13497197Sstephh {
13507197Sstephh if (anp->u.arrow.lhs->t == T_ARROW) {
13517197Sstephh anp->u.arrow.lhs->u.arrow.parent = anp;
13527197Sstephh find_first_arrow(infop, anp->u.arrow.lhs);
13537197Sstephh } else
13547197Sstephh vmatch(infop, anp->u.arrow.lhs, NULL, anp);
13557197Sstephh }
13567197Sstephh
13577197Sstephh static void
cp_reset(struct node * np)13580Sstevel@tonic-gate cp_reset(struct node *np)
13590Sstevel@tonic-gate {
13600Sstevel@tonic-gate if (np == NULL)
13610Sstevel@tonic-gate return;
13620Sstevel@tonic-gate switch (np->t) {
13630Sstevel@tonic-gate case T_NAME:
13640Sstevel@tonic-gate np->u.name.cp = NULL;
13650Sstevel@tonic-gate cp_reset(np->u.name.next);
13660Sstevel@tonic-gate break;
13670Sstevel@tonic-gate
13680Sstevel@tonic-gate case T_LIST:
13690Sstevel@tonic-gate cp_reset(np->u.expr.left);
13700Sstevel@tonic-gate cp_reset(np->u.expr.right);
13710Sstevel@tonic-gate break;
13720Sstevel@tonic-gate
13730Sstevel@tonic-gate case T_ARROW:
13740Sstevel@tonic-gate cp_reset(np->u.arrow.lhs);
13750Sstevel@tonic-gate cp_reset(np->u.arrow.rhs);
13760Sstevel@tonic-gate break;
13770Sstevel@tonic-gate
13780Sstevel@tonic-gate case T_EVENT:
13790Sstevel@tonic-gate cp_reset(np->u.event.epname);
13800Sstevel@tonic-gate break;
13810Sstevel@tonic-gate }
13820Sstevel@tonic-gate }
13830Sstevel@tonic-gate
13840Sstevel@tonic-gate /*
13850Sstevel@tonic-gate * itree_create -- apply the current config to the current parse tree
13860Sstevel@tonic-gate *
13870Sstevel@tonic-gate * returns a lut mapping fully-instance-qualified names to struct events.
13880Sstevel@tonic-gate *
13890Sstevel@tonic-gate */
13900Sstevel@tonic-gate struct lut *
itree_create(struct config * croot)13910Sstevel@tonic-gate itree_create(struct config *croot)
13920Sstevel@tonic-gate {
13930Sstevel@tonic-gate struct lut *retval;
13940Sstevel@tonic-gate struct node *propnp;
13954436Sstephh extern int alloc_total();
13964436Sstephh int init_size;
13970Sstevel@tonic-gate
13980Sstevel@tonic-gate Ninfo.lut = NULL;
13990Sstevel@tonic-gate Ninfo.croot = croot;
14004436Sstephh init_size = alloc_total();
14014436Sstephh out(O_ALTFP|O_STAMP, "start itree_create using %d bytes", init_size);
14020Sstevel@tonic-gate for (propnp = Props; propnp; propnp = propnp->u.stmt.next) {
14030Sstevel@tonic-gate struct node *anp = propnp->u.stmt.np;
14040Sstevel@tonic-gate
14050Sstevel@tonic-gate ASSERTeq(anp->t, T_ARROW, ptree_nodetype2str);
14060Sstevel@tonic-gate
14074436Sstephh if (!anp->u.arrow.needed)
14084436Sstephh continue;
14090Sstevel@tonic-gate Ninfo.anp = anp;
14100Sstevel@tonic-gate Ninfo.ex = NULL;
14110Sstevel@tonic-gate
14120Sstevel@tonic-gate generate_arrownp(anp);
14137197Sstephh anp->u.arrow.parent = NULL;
14147197Sstephh find_first_arrow(&Ninfo, anp);
14150Sstevel@tonic-gate
14160Sstevel@tonic-gate if (Ninfo.ex) {
14170Sstevel@tonic-gate lut_free(Ninfo.ex, iterinfo_destructor, NULL);
14180Sstevel@tonic-gate Ninfo.ex = NULL;
14190Sstevel@tonic-gate }
14200Sstevel@tonic-gate cp_reset(anp);
14210Sstevel@tonic-gate }
14220Sstevel@tonic-gate
14234436Sstephh out(O_ALTFP|O_STAMP, "itree_create added %d bytes",
14244436Sstephh alloc_total() - init_size);
14250Sstevel@tonic-gate retval = Ninfo.lut;
14260Sstevel@tonic-gate Ninfo.lut = NULL;
14270Sstevel@tonic-gate return (retval);
14280Sstevel@tonic-gate }
14290Sstevel@tonic-gate
14304436Sstephh /*
14314436Sstephh * initial first pass of the rules.
14324436Sstephh * We don't use the config at all. Just check the last part of the pathname
14334436Sstephh * in the rules. If this matches the last part of the pathname in the first
14344436Sstephh * ereport, then set pathname to the pathname in the ereport. If not then
14354436Sstephh * set pathname to just the last part of pathname with instance number 0.
14364436Sstephh * Constraints are ignored and all nork values are set to 0. If after all that
14374436Sstephh * any rules can still not be associated with the ereport, then they are set
14384436Sstephh * to not needed in prune_propagations() and ignored in the real itree_create()
14394436Sstephh * which follows.
14404436Sstephh */
14414436Sstephh
14424436Sstephh static struct event *
add_event_dummy(struct node * np,const struct ipath * ipp)14434436Sstephh add_event_dummy(struct node *np, const struct ipath *ipp)
14444436Sstephh {
14454436Sstephh struct event *ret;
14464436Sstephh struct event searchevent; /* just used for searching */
14474436Sstephh extern struct ipath *ipath_dummy(struct node *, struct ipath *);
14489874SStephen.Hanson@Sun.COM struct ipath *ipp_un;
14499874SStephen.Hanson@Sun.COM extern struct ipath *ipath_for_usednames(struct node *);
14504436Sstephh
14514436Sstephh searchevent.enode = np;
14524436Sstephh searchevent.ipp = ipath_dummy(np->u.event.epname, (struct ipath *)ipp);
14539874SStephen.Hanson@Sun.COM ipp_un = ipath_for_usednames(np->u.event.epname);
14544436Sstephh if ((ret = lut_lookup(Ninfo.lut, (void *)&searchevent,
14554436Sstephh (lut_cmp)event_cmp)) != NULL)
14564436Sstephh return (ret);
14574436Sstephh
14584436Sstephh ret = alloc_xmalloc(sizeof (*ret));
14594436Sstephh bzero(ret, sizeof (*ret));
14604436Sstephh ret->t = np->u.event.ename->u.name.t;
14614436Sstephh ret->enode = np;
14624436Sstephh ret->ipp = searchevent.ipp;
14639874SStephen.Hanson@Sun.COM ret->ipp_un = ipp_un;
14644436Sstephh Ninfo.lut = lut_add(Ninfo.lut, (void *)ret, (void *)ret,
14654436Sstephh (lut_cmp)event_cmp);
14664436Sstephh return (ret);
14674436Sstephh }
14684436Sstephh
14694436Sstephh /*ARGSUSED*/
14704436Sstephh struct lut *
itree_create_dummy(const char * e0class,const struct ipath * e0ipp)14714436Sstephh itree_create_dummy(const char *e0class, const struct ipath *e0ipp)
14724436Sstephh {
14734436Sstephh struct node *propnp;
14744436Sstephh struct event *frome, *toe;
14754436Sstephh struct bubble *frombp, *tobp;
14764436Sstephh struct arrow *arrowp;
14774436Sstephh struct node *src, *dst, *slst, *dlst, *arrownp, *oldarrownp;
14784436Sstephh int gen = 0;
14794436Sstephh extern int alloc_total();
14804436Sstephh int init_size;
14814436Sstephh
14824436Sstephh Ninfo.lut = NULL;
14834436Sstephh init_size = alloc_total();
14844436Sstephh out(O_ALTFP|O_STAMP, "start itree_create using %d bytes", init_size);
14854436Sstephh for (propnp = Props; propnp; propnp = propnp->u.stmt.next) {
14864436Sstephh arrownp = propnp->u.stmt.np;
14874436Sstephh while (arrownp) {
14884436Sstephh gen++;
14894436Sstephh dlst = arrownp->u.arrow.rhs;
14904436Sstephh slst = arrownp->u.arrow.lhs;
14914436Sstephh oldarrownp = arrownp;
14924436Sstephh if (slst->t == T_ARROW) {
14934436Sstephh arrownp = slst;
14944436Sstephh slst = slst->u.arrow.rhs;
14954436Sstephh } else {
14964436Sstephh arrownp = NULL;
14974436Sstephh }
14984436Sstephh while (slst) {
14994436Sstephh if (slst->t == T_LIST) {
15004436Sstephh src = slst->u.expr.right;
15014436Sstephh slst = slst->u.expr.left;
15024436Sstephh } else {
15034436Sstephh src = slst;
15044436Sstephh slst = NULL;
15054436Sstephh }
15064436Sstephh frome = add_event_dummy(src, e0ipp);
15074436Sstephh frombp = itree_add_bubble(frome, B_FROM, 0, 0);
15084436Sstephh while (dlst) {
15094436Sstephh if (dlst->t == T_LIST) {
15104436Sstephh dst = dlst->u.expr.right;
15114436Sstephh dlst = dlst->u.expr.left;
15124436Sstephh } else {
15134436Sstephh dst = dlst;
15144436Sstephh dlst = NULL;
15154436Sstephh }
15164436Sstephh arrowp = alloc_xmalloc(
15174436Sstephh sizeof (struct arrow));
15184436Sstephh bzero(arrowp, sizeof (struct arrow));
15194436Sstephh arrowp->pnode = oldarrownp;
15204436Sstephh toe = add_event_dummy(dst, e0ipp);
15214436Sstephh tobp = itree_add_bubble(toe, B_TO, 0,
15224436Sstephh gen);
15234436Sstephh arrowp->tail = frombp;
15244436Sstephh arrowp->head = tobp;
15254436Sstephh add_arrow(frombp, arrowp);
15264436Sstephh add_arrow(tobp, arrowp);
15274436Sstephh arrow_add_within(arrowp,
15284436Sstephh dst->u.event.declp->u.stmt.np->
15294436Sstephh u.event.eexprlist);
15304436Sstephh arrow_add_within(arrowp,
15314436Sstephh dst->u.event.eexprlist);
15324436Sstephh }
15334436Sstephh }
15344436Sstephh }
15354436Sstephh }
15364436Sstephh out(O_ALTFP|O_STAMP, "itree_create added %d bytes",
15374436Sstephh alloc_total() - init_size);
15384436Sstephh return (Ninfo.lut);
15394436Sstephh }
15404436Sstephh
15410Sstevel@tonic-gate void
itree_free(struct lut * lutp)15420Sstevel@tonic-gate itree_free(struct lut *lutp)
15430Sstevel@tonic-gate {
15444436Sstephh int init_size;
15454436Sstephh
15464436Sstephh init_size = alloc_total();
15474436Sstephh out(O_ALTFP|O_STAMP, "start itree_free");
15480Sstevel@tonic-gate lut_free(lutp, itree_destructor, NULL);
15494436Sstephh out(O_ALTFP|O_STAMP, "itree_free freed %d bytes",
15504436Sstephh init_size - alloc_total());
15510Sstevel@tonic-gate }
15520Sstevel@tonic-gate
15531865Sdilpreet void
itree_prune(struct lut * lutp)15541865Sdilpreet itree_prune(struct lut *lutp)
15551865Sdilpreet {
15564436Sstephh int init_size;
15570Sstevel@tonic-gate
15584436Sstephh init_size = alloc_total();
15594436Sstephh out(O_ALTFP|O_STAMP, "start itree_prune");
15604436Sstephh lut_walk(lutp, itree_pruner, NULL);
15614436Sstephh out(O_ALTFP|O_STAMP, "itree_prune freed %d bytes",
15624436Sstephh init_size - alloc_total());
15630Sstevel@tonic-gate }
15640Sstevel@tonic-gate
15650Sstevel@tonic-gate void
itree_pevent_brief(int flags,struct event * ep)15660Sstevel@tonic-gate itree_pevent_brief(int flags, struct event *ep)
15670Sstevel@tonic-gate {
15680Sstevel@tonic-gate ASSERT(ep != NULL);
15690Sstevel@tonic-gate ASSERT(ep->enode != NULL);
15700Sstevel@tonic-gate ASSERT(ep->ipp != NULL);
15710Sstevel@tonic-gate
15720Sstevel@tonic-gate ipath_print(flags, ep->enode->u.event.ename->u.name.s, ep->ipp);
15730Sstevel@tonic-gate }
15740Sstevel@tonic-gate
15750Sstevel@tonic-gate /*ARGSUSED*/
15760Sstevel@tonic-gate static void
itree_pevent(struct event * lhs,struct event * ep,void * arg)15770Sstevel@tonic-gate itree_pevent(struct event *lhs, struct event *ep, void *arg)
15780Sstevel@tonic-gate {
15790Sstevel@tonic-gate struct plut_wlk_data propd;
15800Sstevel@tonic-gate struct bubble *bp;
15816277Scy152378 int flags = (int)(intptr_t)arg;
15820Sstevel@tonic-gate
15830Sstevel@tonic-gate itree_pevent_brief(flags, ep);
15840Sstevel@tonic-gate if (ep->t == N_EREPORT)
15850Sstevel@tonic-gate out(flags, " (count %d)", ep->count);
15860Sstevel@tonic-gate else
15870Sstevel@tonic-gate out(flags, NULL);
15880Sstevel@tonic-gate
15890Sstevel@tonic-gate if (ep->props) {
15900Sstevel@tonic-gate propd.flags = flags;
15910Sstevel@tonic-gate propd.first = 1;
15920Sstevel@tonic-gate out(flags, "Properties:");
15930Sstevel@tonic-gate lut_walk(ep->props, ptree_plut, (void *)&propd);
15940Sstevel@tonic-gate }
15950Sstevel@tonic-gate
15960Sstevel@tonic-gate for (bp = itree_next_bubble(ep, NULL); bp;
15970Sstevel@tonic-gate bp = itree_next_bubble(ep, bp)) {
15980Sstevel@tonic-gate /* Print only TO bubbles in this loop */
15990Sstevel@tonic-gate if (bp->t != B_TO)
16000Sstevel@tonic-gate continue;
16010Sstevel@tonic-gate itree_pbubble(flags, bp);
16020Sstevel@tonic-gate }
16030Sstevel@tonic-gate
16040Sstevel@tonic-gate for (bp = itree_next_bubble(ep, NULL); bp;
16050Sstevel@tonic-gate bp = itree_next_bubble(ep, bp)) {
16060Sstevel@tonic-gate /* Print only INHIBIT bubbles in this loop */
16070Sstevel@tonic-gate if (bp->t != B_INHIBIT)
16080Sstevel@tonic-gate continue;
16090Sstevel@tonic-gate itree_pbubble(flags, bp);
16100Sstevel@tonic-gate }
16110Sstevel@tonic-gate
16120Sstevel@tonic-gate for (bp = itree_next_bubble(ep, NULL); bp;
16130Sstevel@tonic-gate bp = itree_next_bubble(ep, bp)) {
16140Sstevel@tonic-gate /* Print only FROM bubbles in this loop */
16150Sstevel@tonic-gate if (bp->t != B_FROM)
16160Sstevel@tonic-gate continue;
16170Sstevel@tonic-gate itree_pbubble(flags, bp);
16180Sstevel@tonic-gate }
16190Sstevel@tonic-gate }
16200Sstevel@tonic-gate
16210Sstevel@tonic-gate static void
itree_pbubble(int flags,struct bubble * bp)16220Sstevel@tonic-gate itree_pbubble(int flags, struct bubble *bp)
16230Sstevel@tonic-gate {
16240Sstevel@tonic-gate struct constraintlist *cp;
16250Sstevel@tonic-gate struct arrowlist *ap;
16260Sstevel@tonic-gate
16270Sstevel@tonic-gate ASSERT(bp != NULL);
16280Sstevel@tonic-gate
16290Sstevel@tonic-gate out(flags|O_NONL, " ");
16300Sstevel@tonic-gate if (bp->mark)
16310Sstevel@tonic-gate out(flags|O_NONL, "*");
16320Sstevel@tonic-gate else
16330Sstevel@tonic-gate out(flags|O_NONL, " ");
16340Sstevel@tonic-gate if (bp->t == B_FROM)
16350Sstevel@tonic-gate out(flags|O_NONL, "N=%d to:", bp->nork);
16360Sstevel@tonic-gate else if (bp->t == B_TO)
16370Sstevel@tonic-gate out(flags|O_NONL, "K=%d from:", bp->nork);
16380Sstevel@tonic-gate else
16390Sstevel@tonic-gate out(flags|O_NONL, "K=%d masked from:", bp->nork);
16400Sstevel@tonic-gate
16410Sstevel@tonic-gate if (bp->t == B_TO || bp->t == B_INHIBIT) {
16420Sstevel@tonic-gate for (ap = itree_next_arrow(bp, NULL); ap;
16430Sstevel@tonic-gate ap = itree_next_arrow(bp, ap)) {
16440Sstevel@tonic-gate ASSERT(ap->arrowp->head == bp);
16450Sstevel@tonic-gate ASSERT(ap->arrowp->tail != NULL);
16460Sstevel@tonic-gate ASSERT(ap->arrowp->tail->myevent != NULL);
16470Sstevel@tonic-gate out(flags|O_NONL, " ");
16480Sstevel@tonic-gate itree_pevent_brief(flags, ap->arrowp->tail->myevent);
16490Sstevel@tonic-gate }
16500Sstevel@tonic-gate out(flags, NULL);
16510Sstevel@tonic-gate return;
16520Sstevel@tonic-gate }
16530Sstevel@tonic-gate
16540Sstevel@tonic-gate for (ap = itree_next_arrow(bp, NULL); ap;
16550Sstevel@tonic-gate ap = itree_next_arrow(bp, ap)) {
16560Sstevel@tonic-gate ASSERT(ap->arrowp->tail == bp);
16570Sstevel@tonic-gate ASSERT(ap->arrowp->head != NULL);
16580Sstevel@tonic-gate ASSERT(ap->arrowp->head->myevent != NULL);
16590Sstevel@tonic-gate
16600Sstevel@tonic-gate out(flags|O_NONL, " ");
16610Sstevel@tonic-gate itree_pevent_brief(flags, ap->arrowp->head->myevent);
16620Sstevel@tonic-gate
16630Sstevel@tonic-gate out(flags|O_NONL, " ");
16640Sstevel@tonic-gate ptree_timeval(flags, &ap->arrowp->mindelay);
16650Sstevel@tonic-gate out(flags|O_NONL, ",");
16660Sstevel@tonic-gate ptree_timeval(flags, &ap->arrowp->maxdelay);
16670Sstevel@tonic-gate
16680Sstevel@tonic-gate /* Display anything from the propogation node? */
16690Sstevel@tonic-gate out(O_VERB3|O_NONL, " <%s:%d>",
16700Sstevel@tonic-gate ap->arrowp->pnode->file, ap->arrowp->pnode->line);
16710Sstevel@tonic-gate
16720Sstevel@tonic-gate if (itree_next_constraint(ap->arrowp, NULL))
16730Sstevel@tonic-gate out(flags|O_NONL, " {");
16740Sstevel@tonic-gate
16750Sstevel@tonic-gate for (cp = itree_next_constraint(ap->arrowp, NULL); cp;
16760Sstevel@tonic-gate cp = itree_next_constraint(ap->arrowp, cp)) {
16770Sstevel@tonic-gate ptree(flags, cp->cnode, 1, 0);
16780Sstevel@tonic-gate if (itree_next_constraint(ap->arrowp, cp))
16790Sstevel@tonic-gate out(flags|O_NONL, ", ");
16800Sstevel@tonic-gate }
16810Sstevel@tonic-gate
16820Sstevel@tonic-gate if (itree_next_constraint(ap->arrowp, NULL))
16830Sstevel@tonic-gate out(flags|O_NONL, "}");
16840Sstevel@tonic-gate }
16850Sstevel@tonic-gate out(flags, NULL);
16860Sstevel@tonic-gate }
16870Sstevel@tonic-gate
16880Sstevel@tonic-gate void
itree_ptree(int flags,struct lut * itp)16890Sstevel@tonic-gate itree_ptree(int flags, struct lut *itp)
16900Sstevel@tonic-gate {
16916277Scy152378 lut_walk(itp, (lut_cb)itree_pevent, (void *)(intptr_t)flags);
16920Sstevel@tonic-gate }
16930Sstevel@tonic-gate
16940Sstevel@tonic-gate /*ARGSUSED*/
16950Sstevel@tonic-gate static void
itree_destructor(void * left,void * right,void * arg)16960Sstevel@tonic-gate itree_destructor(void *left, void *right, void *arg)
16970Sstevel@tonic-gate {
16980Sstevel@tonic-gate struct event *ep = (struct event *)right;
16990Sstevel@tonic-gate struct bubble *nextbub, *bub;
17000Sstevel@tonic-gate
17010Sstevel@tonic-gate /* Free the properties */
17021865Sdilpreet if (ep->props)
17031865Sdilpreet lut_free(ep->props, instances_destructor, NULL);
17040Sstevel@tonic-gate
17051414Scindi /* Free the payload properties */
17061865Sdilpreet if (ep->payloadprops)
17071865Sdilpreet lut_free(ep->payloadprops, payloadprops_destructor, NULL);
17081414Scindi
17097197Sstephh /* Free the serd properties */
17107197Sstephh if (ep->serdprops)
17117197Sstephh lut_free(ep->serdprops, serdprops_destructor, NULL);
17127197Sstephh
17130Sstevel@tonic-gate /* Free my bubbles */
17140Sstevel@tonic-gate for (bub = ep->bubbles; bub != NULL; ) {
17150Sstevel@tonic-gate nextbub = bub->next;
17160Sstevel@tonic-gate /*
17170Sstevel@tonic-gate * Free arrows if they are FROM me. Free arrowlists on
17180Sstevel@tonic-gate * other types of bubbles (but not the attached arrows,
17190Sstevel@tonic-gate * which will be freed when we free the originating
17200Sstevel@tonic-gate * bubble.
17210Sstevel@tonic-gate */
17220Sstevel@tonic-gate if (bub->t == B_FROM)
17230Sstevel@tonic-gate itree_free_arrowlists(bub, 1);
17240Sstevel@tonic-gate else
17250Sstevel@tonic-gate itree_free_arrowlists(bub, 0);
17260Sstevel@tonic-gate itree_free_bubble(bub);
17270Sstevel@tonic-gate bub = nextbub;
17280Sstevel@tonic-gate }
17290Sstevel@tonic-gate
17300Sstevel@tonic-gate if (ep->nvp != NULL)
17310Sstevel@tonic-gate nvlist_free(ep->nvp);
17324436Sstephh alloc_xfree(ep, sizeof (*ep));
17330Sstevel@tonic-gate }
17340Sstevel@tonic-gate
17351865Sdilpreet /*ARGSUSED*/
17361865Sdilpreet static void
itree_pruner(void * left,void * right,void * arg)17371865Sdilpreet itree_pruner(void *left, void *right, void *arg)
17381865Sdilpreet {
17391865Sdilpreet struct event *ep = (struct event *)right;
17401865Sdilpreet struct bubble *nextbub, *bub;
17411865Sdilpreet
17421865Sdilpreet if (ep->keep_in_tree)
17431865Sdilpreet return;
17441865Sdilpreet
17451865Sdilpreet /* Free the properties */
17461865Sdilpreet lut_free(ep->props, instances_destructor, NULL);
17471865Sdilpreet
17481865Sdilpreet /* Free the payload properties */
17491865Sdilpreet lut_free(ep->payloadprops, payloadprops_destructor, NULL);
17501865Sdilpreet
17517197Sstephh /* Free the serd properties */
17527197Sstephh lut_free(ep->serdprops, serdprops_destructor, NULL);
17537197Sstephh
17541865Sdilpreet /* Free my bubbles */
17551865Sdilpreet for (bub = ep->bubbles; bub != NULL; ) {
17561865Sdilpreet nextbub = bub->next;
17571865Sdilpreet itree_prune_arrowlists(bub);
17581865Sdilpreet itree_free_bubble(bub);
17591865Sdilpreet bub = nextbub;
17601865Sdilpreet }
17611865Sdilpreet
17621865Sdilpreet if (ep->nvp != NULL)
17631865Sdilpreet nvlist_free(ep->nvp);
17641865Sdilpreet ep->props = NULL;
17651865Sdilpreet ep->payloadprops = NULL;
17667197Sstephh ep->serdprops = NULL;
17671865Sdilpreet ep->bubbles = NULL;
17681865Sdilpreet ep->nvp = NULL;
17691865Sdilpreet }
17701865Sdilpreet
17710Sstevel@tonic-gate static void
itree_free_bubble(struct bubble * freeme)17720Sstevel@tonic-gate itree_free_bubble(struct bubble *freeme)
17730Sstevel@tonic-gate {
17744436Sstephh alloc_xfree(freeme, sizeof (*freeme));
17750Sstevel@tonic-gate }
17760Sstevel@tonic-gate
17770Sstevel@tonic-gate static struct bubble *
itree_add_bubble(struct event * eventp,enum bubbletype btype,int nork,int gen)17780Sstevel@tonic-gate itree_add_bubble(struct event *eventp, enum bubbletype btype, int nork, int gen)
17790Sstevel@tonic-gate {
17800Sstevel@tonic-gate struct bubble *prev = NULL;
17810Sstevel@tonic-gate struct bubble *curr;
17820Sstevel@tonic-gate struct bubble *newb;
17830Sstevel@tonic-gate
17840Sstevel@tonic-gate /* Use existing bubbles as appropriate when possible */
17850Sstevel@tonic-gate for (curr = eventp->bubbles;
17860Sstevel@tonic-gate curr != NULL;
17870Sstevel@tonic-gate prev = curr, curr = curr->next) {
17880Sstevel@tonic-gate if (btype == B_TO && curr->t == B_TO) {
17890Sstevel@tonic-gate /* see if an existing "to" bubble works for us */
17900Sstevel@tonic-gate if (gen == curr->gen)
17910Sstevel@tonic-gate return (curr); /* matched gen number */
17920Sstevel@tonic-gate else if (nork == 1 && curr->nork == 1) {
17930Sstevel@tonic-gate curr->gen = gen;
17940Sstevel@tonic-gate return (curr); /* coalesce K==1 bubbles */
17950Sstevel@tonic-gate }
17960Sstevel@tonic-gate } else if (btype == B_FROM && curr->t == B_FROM) {
17970Sstevel@tonic-gate /* see if an existing "from" bubble works for us */
17980Sstevel@tonic-gate if ((nork == N_IS_ALL && curr->nork == N_IS_ALL) ||
17990Sstevel@tonic-gate (nork == 0 && curr->nork == 0))
18000Sstevel@tonic-gate return (curr);
18010Sstevel@tonic-gate }
18020Sstevel@tonic-gate }
18030Sstevel@tonic-gate
18044436Sstephh newb = alloc_xmalloc(sizeof (struct bubble));
18050Sstevel@tonic-gate newb->next = NULL;
18060Sstevel@tonic-gate newb->t = btype;
18070Sstevel@tonic-gate newb->myevent = eventp;
18080Sstevel@tonic-gate newb->nork = nork;
18090Sstevel@tonic-gate newb->mark = 0;
18100Sstevel@tonic-gate newb->gen = gen;
18110Sstevel@tonic-gate newb->arrows = NULL;
18120Sstevel@tonic-gate
18130Sstevel@tonic-gate if (prev == NULL)
18140Sstevel@tonic-gate eventp->bubbles = newb;
18150Sstevel@tonic-gate else
18160Sstevel@tonic-gate prev->next = newb;
18170Sstevel@tonic-gate
18180Sstevel@tonic-gate return (newb);
18190Sstevel@tonic-gate }
18200Sstevel@tonic-gate
18210Sstevel@tonic-gate struct bubble *
itree_next_bubble(struct event * eventp,struct bubble * last)18220Sstevel@tonic-gate itree_next_bubble(struct event *eventp, struct bubble *last)
18230Sstevel@tonic-gate {
18240Sstevel@tonic-gate struct bubble *next;
18250Sstevel@tonic-gate
18260Sstevel@tonic-gate for (;;) {
18270Sstevel@tonic-gate if (last != NULL)
18280Sstevel@tonic-gate next = last->next;
18290Sstevel@tonic-gate else
18300Sstevel@tonic-gate next = eventp->bubbles;
18310Sstevel@tonic-gate
18320Sstevel@tonic-gate if (next == NULL || next->arrows != NULL)
18330Sstevel@tonic-gate return (next);
18340Sstevel@tonic-gate
18350Sstevel@tonic-gate /* bubble was empty, skip it */
18360Sstevel@tonic-gate last = next;
18370Sstevel@tonic-gate }
18380Sstevel@tonic-gate }
18390Sstevel@tonic-gate
18400Sstevel@tonic-gate static void
add_arrow(struct bubble * bp,struct arrow * ap)18410Sstevel@tonic-gate add_arrow(struct bubble *bp, struct arrow *ap)
18420Sstevel@tonic-gate {
18430Sstevel@tonic-gate struct arrowlist *prev = NULL;
18440Sstevel@tonic-gate struct arrowlist *curr;
18450Sstevel@tonic-gate struct arrowlist *newal;
18460Sstevel@tonic-gate
18474436Sstephh newal = alloc_xmalloc(sizeof (struct arrowlist));
18480Sstevel@tonic-gate bzero(newal, sizeof (struct arrowlist));
18490Sstevel@tonic-gate newal->arrowp = ap;
18500Sstevel@tonic-gate
18510Sstevel@tonic-gate curr = itree_next_arrow(bp, NULL);
18520Sstevel@tonic-gate while (curr != NULL) {
18530Sstevel@tonic-gate prev = curr;
18540Sstevel@tonic-gate curr = itree_next_arrow(bp, curr);
18550Sstevel@tonic-gate }
18560Sstevel@tonic-gate
18570Sstevel@tonic-gate if (prev == NULL)
18580Sstevel@tonic-gate bp->arrows = newal;
18590Sstevel@tonic-gate else
18600Sstevel@tonic-gate prev->next = newal;
18610Sstevel@tonic-gate }
18620Sstevel@tonic-gate
18630Sstevel@tonic-gate static struct arrow *
itree_add_arrow(struct node * apnode,struct node * fromevent,struct node * toevent,struct lut * ex)18644436Sstephh itree_add_arrow(struct node *apnode, struct node *fromevent,
18654436Sstephh struct node *toevent, struct lut *ex)
18660Sstevel@tonic-gate {
18670Sstevel@tonic-gate struct arrow *newa;
18680Sstevel@tonic-gate
18694436Sstephh newa = alloc_xmalloc(sizeof (struct arrow));
18701414Scindi bzero(newa, sizeof (struct arrow));
18710Sstevel@tonic-gate newa->pnode = apnode;
18720Sstevel@tonic-gate newa->constraints = NULL;
18730Sstevel@tonic-gate
18740Sstevel@tonic-gate /*
18750Sstevel@tonic-gate * Set default delays, then try to re-set them from
18760Sstevel@tonic-gate * any within() constraints.
18770Sstevel@tonic-gate */
18780Sstevel@tonic-gate newa->mindelay = newa->maxdelay = 0ULL;
18790Sstevel@tonic-gate if (itree_set_arrow_traits(newa, fromevent, toevent, ex) == 0) {
18804436Sstephh alloc_xfree(newa, sizeof (struct arrow));
18810Sstevel@tonic-gate return (NULL);
18820Sstevel@tonic-gate }
18830Sstevel@tonic-gate
18840Sstevel@tonic-gate return (newa);
18850Sstevel@tonic-gate }
18860Sstevel@tonic-gate
18870Sstevel@tonic-gate /* returns false if traits show that arrow should not be added after all */
18880Sstevel@tonic-gate static int
itree_set_arrow_traits(struct arrow * ap,struct node * fromev,struct node * toev,struct lut * ex)18890Sstevel@tonic-gate itree_set_arrow_traits(struct arrow *ap, struct node *fromev,
18900Sstevel@tonic-gate struct node *toev, struct lut *ex)
18910Sstevel@tonic-gate {
18924436Sstephh struct node *events[] = { NULL, NULL, NULL };
18930Sstevel@tonic-gate struct node *newc = NULL;
18940Sstevel@tonic-gate
18950Sstevel@tonic-gate ASSERTeq(fromev->t, T_EVENT, ptree_nodetype2str);
18960Sstevel@tonic-gate ASSERTeq(toev->t, T_EVENT, ptree_nodetype2str);
18970Sstevel@tonic-gate
18980Sstevel@tonic-gate /*
18990Sstevel@tonic-gate * search for the within values first on the declaration of
19000Sstevel@tonic-gate * the destination event, and then on the prop. this allows
19010Sstevel@tonic-gate * one to specify a "default" within by putting it on the
19020Sstevel@tonic-gate * declaration, but then allow overriding on the prop statement.
19030Sstevel@tonic-gate */
19040Sstevel@tonic-gate arrow_add_within(ap, toev->u.event.declp->u.stmt.np->u.event.eexprlist);
19050Sstevel@tonic-gate arrow_add_within(ap, toev->u.event.eexprlist);
19060Sstevel@tonic-gate
19070Sstevel@tonic-gate /*
19080Sstevel@tonic-gate * handle any global constraints inherited from the
19090Sstevel@tonic-gate * "fromev" event's declaration
19100Sstevel@tonic-gate */
19110Sstevel@tonic-gate ASSERT(fromev->u.event.declp != NULL);
19120Sstevel@tonic-gate ASSERT(fromev->u.event.declp->u.stmt.np != NULL);
19130Sstevel@tonic-gate
19140Sstevel@tonic-gate #ifdef notdef
19150Sstevel@tonic-gate /* XXX not quite ready to evaluate constraints from decls yet */
19160Sstevel@tonic-gate if (fromev->u.event.declp->u.stmt.np->u.event.eexprlist)
19170Sstevel@tonic-gate (void) itree_add_constraint(ap,
19180Sstevel@tonic-gate fromev->u.event.declp->u.stmt.np->u.event.eexprlist);
19190Sstevel@tonic-gate #endif /* notdef */
19200Sstevel@tonic-gate
19210Sstevel@tonic-gate /* handle constraints on the from event in the prop statement */
19224436Sstephh events[0] = fromev;
19234436Sstephh events[1] = toev;
19244436Sstephh if (eval_potential(fromev->u.event.eexprlist, ex, events, &newc,
19252318Sstephh Ninfo.croot) == 0)
19260Sstevel@tonic-gate return (0); /* constraint disallows arrow */
19270Sstevel@tonic-gate
19280Sstevel@tonic-gate /*
19290Sstevel@tonic-gate * handle any global constraints inherited from the
19300Sstevel@tonic-gate * "toev" event's declaration
19310Sstevel@tonic-gate */
19320Sstevel@tonic-gate ASSERT(toev->u.event.declp != NULL);
19330Sstevel@tonic-gate ASSERT(toev->u.event.declp->u.stmt.np != NULL);
19340Sstevel@tonic-gate
19350Sstevel@tonic-gate #ifdef notdef
19360Sstevel@tonic-gate /* XXX not quite ready to evaluate constraints from decls yet */
19370Sstevel@tonic-gate if (toev->u.event.declp->u.stmt.np->u.event.eexprlist)
19380Sstevel@tonic-gate (void) itree_add_constraint(ap,
19390Sstevel@tonic-gate toev->u.event.declp->u.stmt.np->u.event.eexprlist);
19400Sstevel@tonic-gate #endif /* notdef */
19410Sstevel@tonic-gate
19420Sstevel@tonic-gate /* handle constraints on the to event in the prop statement */
19434436Sstephh events[0] = toev;
19444436Sstephh events[1] = fromev;
19454436Sstephh if (eval_potential(toev->u.event.eexprlist, ex, events, &newc,
19462318Sstephh Ninfo.croot) == 0) {
19471865Sdilpreet if (newc != NULL)
19481865Sdilpreet tree_free(newc);
19490Sstevel@tonic-gate return (0); /* constraint disallows arrow */
19501865Sdilpreet }
19510Sstevel@tonic-gate
19520Sstevel@tonic-gate /* if we came up with any deferred constraints, add them to arrow */
19534436Sstephh if (newc != NULL) {
19544436Sstephh out(O_ALTFP|O_VERB3, "(deferred constraints)");
19551414Scindi (void) itree_add_constraint(ap, iexpr(newc));
19564436Sstephh }
19570Sstevel@tonic-gate
19580Sstevel@tonic-gate return (1); /* constraints allow arrow */
19590Sstevel@tonic-gate }
19600Sstevel@tonic-gate
19610Sstevel@tonic-gate /*
19620Sstevel@tonic-gate * Set within() constraint. If the constraint were set multiple times,
19630Sstevel@tonic-gate * the last one would "win".
19640Sstevel@tonic-gate */
19650Sstevel@tonic-gate static void
arrow_add_within(struct arrow * ap,struct node * xpr)19660Sstevel@tonic-gate arrow_add_within(struct arrow *ap, struct node *xpr)
19670Sstevel@tonic-gate {
19680Sstevel@tonic-gate struct node *arglist;
19690Sstevel@tonic-gate
19700Sstevel@tonic-gate /* end of expressions list */
19710Sstevel@tonic-gate if (xpr == NULL)
19720Sstevel@tonic-gate return;
19730Sstevel@tonic-gate
19740Sstevel@tonic-gate switch (xpr->t) {
19750Sstevel@tonic-gate case T_LIST:
19760Sstevel@tonic-gate arrow_add_within(ap, xpr->u.expr.left);
19770Sstevel@tonic-gate arrow_add_within(ap, xpr->u.expr.right);
19780Sstevel@tonic-gate return;
19790Sstevel@tonic-gate case T_FUNC:
19800Sstevel@tonic-gate if (xpr->u.func.s != L_within)
19810Sstevel@tonic-gate return;
19820Sstevel@tonic-gate arglist = xpr->u.func.arglist;
19830Sstevel@tonic-gate switch (arglist->t) {
19840Sstevel@tonic-gate case T_TIMEVAL:
19850Sstevel@tonic-gate ap->mindelay = 0;
19860Sstevel@tonic-gate ap->maxdelay = arglist->u.ull;
19870Sstevel@tonic-gate break;
19880Sstevel@tonic-gate case T_NAME:
19890Sstevel@tonic-gate ASSERT(arglist->u.name.s == L_infinity);
19900Sstevel@tonic-gate ap->mindelay = 0;
19910Sstevel@tonic-gate ap->maxdelay = TIMEVAL_EVENTUALLY;
19920Sstevel@tonic-gate break;
19930Sstevel@tonic-gate case T_LIST:
19940Sstevel@tonic-gate ASSERT(arglist->u.expr.left->t == T_TIMEVAL);
19950Sstevel@tonic-gate ap->mindelay = arglist->u.expr.left->u.ull;
19960Sstevel@tonic-gate switch (arglist->u.expr.right->t) {
19970Sstevel@tonic-gate case T_TIMEVAL:
19980Sstevel@tonic-gate ap->maxdelay = arglist->u.ull;
19990Sstevel@tonic-gate break;
20000Sstevel@tonic-gate case T_NAME:
20010Sstevel@tonic-gate ASSERT(arglist->u.expr.right->u.name.s ==
20020Sstevel@tonic-gate L_infinity);
20030Sstevel@tonic-gate ap->maxdelay = TIMEVAL_EVENTUALLY;
20040Sstevel@tonic-gate break;
20050Sstevel@tonic-gate default:
20060Sstevel@tonic-gate out(O_DIE, "within: unexpected 2nd arg type");
20070Sstevel@tonic-gate }
20080Sstevel@tonic-gate break;
20090Sstevel@tonic-gate default:
20100Sstevel@tonic-gate out(O_DIE, "within: unexpected 1st arg type");
20110Sstevel@tonic-gate }
20120Sstevel@tonic-gate break;
20130Sstevel@tonic-gate default:
20140Sstevel@tonic-gate return;
20150Sstevel@tonic-gate }
20160Sstevel@tonic-gate }
20170Sstevel@tonic-gate
20180Sstevel@tonic-gate static void
itree_free_arrowlists(struct bubble * bubp,int arrows_too)20190Sstevel@tonic-gate itree_free_arrowlists(struct bubble *bubp, int arrows_too)
20200Sstevel@tonic-gate {
20210Sstevel@tonic-gate struct arrowlist *al, *nal;
20220Sstevel@tonic-gate
20230Sstevel@tonic-gate al = bubp->arrows;
20240Sstevel@tonic-gate while (al != NULL) {
20250Sstevel@tonic-gate nal = al->next;
20260Sstevel@tonic-gate if (arrows_too) {
20270Sstevel@tonic-gate itree_free_constraints(al->arrowp);
20284436Sstephh alloc_xfree(al->arrowp, sizeof (struct arrow));
20290Sstevel@tonic-gate }
20304436Sstephh alloc_xfree(al, sizeof (*al));
20310Sstevel@tonic-gate al = nal;
20320Sstevel@tonic-gate }
20330Sstevel@tonic-gate }
20340Sstevel@tonic-gate
20351865Sdilpreet static void
itree_delete_arrow(struct bubble * bubp,struct arrow * arrow)20361865Sdilpreet itree_delete_arrow(struct bubble *bubp, struct arrow *arrow)
20371865Sdilpreet {
20381865Sdilpreet struct arrowlist *al, *oal;
20391865Sdilpreet
20401865Sdilpreet al = bubp->arrows;
20411865Sdilpreet if (al->arrowp == arrow) {
20421865Sdilpreet bubp->arrows = al->next;
20434436Sstephh alloc_xfree(al, sizeof (*al));
20441865Sdilpreet return;
20451865Sdilpreet }
20461865Sdilpreet while (al != NULL) {
20471865Sdilpreet oal = al;
20481865Sdilpreet al = al->next;
20491865Sdilpreet ASSERT(al != NULL);
20501865Sdilpreet if (al->arrowp == arrow) {
20511865Sdilpreet oal->next = al->next;
20524436Sstephh alloc_xfree(al, sizeof (*al));
20531865Sdilpreet return;
20541865Sdilpreet }
20551865Sdilpreet }
20561865Sdilpreet }
20571865Sdilpreet
20581865Sdilpreet static void
itree_prune_arrowlists(struct bubble * bubp)20591865Sdilpreet itree_prune_arrowlists(struct bubble *bubp)
20601865Sdilpreet {
20611865Sdilpreet struct arrowlist *al, *nal;
20621865Sdilpreet
20631865Sdilpreet al = bubp->arrows;
20641865Sdilpreet while (al != NULL) {
20651865Sdilpreet nal = al->next;
20661865Sdilpreet if (bubp->t == B_FROM)
20671865Sdilpreet itree_delete_arrow(al->arrowp->head, al->arrowp);
20681865Sdilpreet else
20691865Sdilpreet itree_delete_arrow(al->arrowp->tail, al->arrowp);
20701865Sdilpreet itree_free_constraints(al->arrowp);
20714436Sstephh alloc_xfree(al->arrowp, sizeof (struct arrow));
20724436Sstephh alloc_xfree(al, sizeof (*al));
20731865Sdilpreet al = nal;
20741865Sdilpreet }
20751865Sdilpreet }
20761865Sdilpreet
20770Sstevel@tonic-gate struct arrowlist *
itree_next_arrow(struct bubble * bubble,struct arrowlist * last)20780Sstevel@tonic-gate itree_next_arrow(struct bubble *bubble, struct arrowlist *last)
20790Sstevel@tonic-gate {
20800Sstevel@tonic-gate struct arrowlist *next;
20810Sstevel@tonic-gate
20820Sstevel@tonic-gate if (last != NULL)
20830Sstevel@tonic-gate next = last->next;
20840Sstevel@tonic-gate else
20850Sstevel@tonic-gate next = bubble->arrows;
20860Sstevel@tonic-gate return (next);
20870Sstevel@tonic-gate }
20880Sstevel@tonic-gate
20890Sstevel@tonic-gate static struct constraintlist *
itree_add_constraint(struct arrow * arrowp,struct node * c)20900Sstevel@tonic-gate itree_add_constraint(struct arrow *arrowp, struct node *c)
20910Sstevel@tonic-gate {
20920Sstevel@tonic-gate struct constraintlist *prev = NULL;
20930Sstevel@tonic-gate struct constraintlist *curr;
20940Sstevel@tonic-gate struct constraintlist *newc;
20950Sstevel@tonic-gate
20960Sstevel@tonic-gate for (curr = arrowp->constraints;
20970Sstevel@tonic-gate curr != NULL;
20984436Sstephh prev = curr, curr = curr->next)
20994436Sstephh ;
21000Sstevel@tonic-gate
21014436Sstephh newc = alloc_xmalloc(sizeof (struct constraintlist));
21020Sstevel@tonic-gate newc->next = NULL;
21030Sstevel@tonic-gate newc->cnode = c;
21040Sstevel@tonic-gate
21050Sstevel@tonic-gate if (prev == NULL)
21060Sstevel@tonic-gate arrowp->constraints = newc;
21070Sstevel@tonic-gate else
21080Sstevel@tonic-gate prev->next = newc;
21090Sstevel@tonic-gate
21100Sstevel@tonic-gate return (newc);
21110Sstevel@tonic-gate }
21120Sstevel@tonic-gate
21130Sstevel@tonic-gate struct constraintlist *
itree_next_constraint(struct arrow * arrowp,struct constraintlist * last)21140Sstevel@tonic-gate itree_next_constraint(struct arrow *arrowp, struct constraintlist *last)
21150Sstevel@tonic-gate {
21160Sstevel@tonic-gate struct constraintlist *next;
21170Sstevel@tonic-gate
21180Sstevel@tonic-gate if (last != NULL)
21190Sstevel@tonic-gate next = last->next;
21200Sstevel@tonic-gate else
21210Sstevel@tonic-gate next = arrowp->constraints;
21220Sstevel@tonic-gate return (next);
21230Sstevel@tonic-gate }
21240Sstevel@tonic-gate
21250Sstevel@tonic-gate static void
itree_free_constraints(struct arrow * ap)21260Sstevel@tonic-gate itree_free_constraints(struct arrow *ap)
21270Sstevel@tonic-gate {
21280Sstevel@tonic-gate struct constraintlist *cl, *ncl;
21290Sstevel@tonic-gate
21300Sstevel@tonic-gate cl = ap->constraints;
21310Sstevel@tonic-gate while (cl != NULL) {
21320Sstevel@tonic-gate ncl = cl->next;
21330Sstevel@tonic-gate ASSERT(cl->cnode != NULL);
21341414Scindi if (!iexpr_cached(cl->cnode))
21351414Scindi tree_free(cl->cnode);
21361865Sdilpreet else
21371865Sdilpreet iexpr_free(cl->cnode);
21384436Sstephh alloc_xfree(cl, sizeof (*cl));
21390Sstevel@tonic-gate cl = ncl;
21400Sstevel@tonic-gate }
21410Sstevel@tonic-gate }
21420Sstevel@tonic-gate
21430Sstevel@tonic-gate const char *
itree_bubbletype2str(enum bubbletype t)21440Sstevel@tonic-gate itree_bubbletype2str(enum bubbletype t)
21450Sstevel@tonic-gate {
21460Sstevel@tonic-gate static char buf[100];
21470Sstevel@tonic-gate
21480Sstevel@tonic-gate switch (t) {
21490Sstevel@tonic-gate case B_FROM: return L_from;
21500Sstevel@tonic-gate case B_TO: return L_to;
21510Sstevel@tonic-gate case B_INHIBIT: return L_inhibit;
21520Sstevel@tonic-gate default:
21530Sstevel@tonic-gate (void) sprintf(buf, "[unexpected bubbletype: %d]", t);
21540Sstevel@tonic-gate return (buf);
21550Sstevel@tonic-gate }
21560Sstevel@tonic-gate }
21570Sstevel@tonic-gate
21580Sstevel@tonic-gate /*
21590Sstevel@tonic-gate * itree_fini -- clean up any half-built itrees
21600Sstevel@tonic-gate */
21610Sstevel@tonic-gate void
itree_fini(void)21620Sstevel@tonic-gate itree_fini(void)
21630Sstevel@tonic-gate {
21640Sstevel@tonic-gate if (Ninfo.lut != NULL) {
21650Sstevel@tonic-gate itree_free(Ninfo.lut);
21660Sstevel@tonic-gate Ninfo.lut = NULL;
21670Sstevel@tonic-gate }
21680Sstevel@tonic-gate if (Ninfo.ex) {
21690Sstevel@tonic-gate lut_free(Ninfo.ex, iterinfo_destructor, NULL);
21700Sstevel@tonic-gate Ninfo.ex = NULL;
21710Sstevel@tonic-gate }
21720Sstevel@tonic-gate }
2173