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 /* 23*4436Sstephh * Copyright 2007 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 #pragma ident "%Z%%M% %I% %E% SMI" 320Sstevel@tonic-gate 330Sstevel@tonic-gate #include <stdio.h> 340Sstevel@tonic-gate #include <ctype.h> 350Sstevel@tonic-gate #include <string.h> 360Sstevel@tonic-gate #include <strings.h> 370Sstevel@tonic-gate #include "alloc.h" 380Sstevel@tonic-gate #include "out.h" 390Sstevel@tonic-gate #include "stable.h" 400Sstevel@tonic-gate #include "literals.h" 410Sstevel@tonic-gate #include "lut.h" 420Sstevel@tonic-gate #include "tree.h" 430Sstevel@tonic-gate #include "ptree.h" 440Sstevel@tonic-gate #include "itree.h" 450Sstevel@tonic-gate #include "ipath.h" 461414Scindi #include "iexpr.h" 470Sstevel@tonic-gate #include "eval.h" 480Sstevel@tonic-gate #include "config.h" 490Sstevel@tonic-gate 500Sstevel@tonic-gate /* 510Sstevel@tonic-gate * struct info contains the state we keep when expanding a prop statement 520Sstevel@tonic-gate * as part of constructing the instance tree. state kept in struct info 530Sstevel@tonic-gate * is the non-recursive stuff -- the stuff that doesn't need to be on 540Sstevel@tonic-gate * the stack. the rest of the state that is passed between all the 550Sstevel@tonic-gate * mutually recursive functions, is required to be on the stack since 560Sstevel@tonic-gate * we need to backtrack and recurse as we do the instance tree construction. 570Sstevel@tonic-gate */ 580Sstevel@tonic-gate struct info { 590Sstevel@tonic-gate struct lut *lut; 600Sstevel@tonic-gate struct node *anp; /* arrow np */ 610Sstevel@tonic-gate struct lut *ex; /* dictionary of explicit iterators */ 620Sstevel@tonic-gate struct config *croot; 630Sstevel@tonic-gate } Ninfo; 640Sstevel@tonic-gate 650Sstevel@tonic-gate /* 660Sstevel@tonic-gate * struct wildcardinfo is used to track wildcarded portions of paths. 670Sstevel@tonic-gate * 680Sstevel@tonic-gate * for example, if the epname of an event is "c/d" and the path "a/b/c/d" 690Sstevel@tonic-gate * exists, the wildcard path ewname is filled in with the path "a/b". when 700Sstevel@tonic-gate * matching is done, epname is temporarily replaced with the concatenation 71*4436Sstephh * of ewname and epname. 720Sstevel@tonic-gate * 730Sstevel@tonic-gate * a linked list of these structs is used to track the expansion of each 740Sstevel@tonic-gate * event node as it is processed in vmatch() --> vmatch_event() calls. 750Sstevel@tonic-gate */ 760Sstevel@tonic-gate struct wildcardinfo { 770Sstevel@tonic-gate struct node *nptop; /* event node fed to vmatch */ 780Sstevel@tonic-gate struct node *oldepname; /* epname without the wildcard part */ 79*4436Sstephh struct node *ewname; /* wildcard path */ 800Sstevel@tonic-gate struct wildcardinfo *next; 810Sstevel@tonic-gate }; 820Sstevel@tonic-gate 83*4436Sstephh static struct wildcardinfo *wcproot = NULL; 84*4436Sstephh 85*4436Sstephh static void vmatch(struct info *infop, struct node *np, struct node *lnp, 86*4436Sstephh struct node *anp); 870Sstevel@tonic-gate static void hmatch(struct info *infop, struct node *np, struct node *nextnp); 880Sstevel@tonic-gate static void itree_pbubble(int flags, struct bubble *bp); 891865Sdilpreet static void itree_pruner(void *left, void *right, void *arg); 900Sstevel@tonic-gate static void itree_destructor(void *left, void *right, void *arg); 910Sstevel@tonic-gate static int itree_set_arrow_traits(struct arrow *ap, struct node *fromev, 920Sstevel@tonic-gate struct node *toev, struct lut *ex); 930Sstevel@tonic-gate static void itree_free_arrowlists(struct bubble *bubp, int arrows_too); 941865Sdilpreet static void itree_prune_arrowlists(struct bubble *bubp); 950Sstevel@tonic-gate static void arrow_add_within(struct arrow *ap, struct node *xpr); 96*4436Sstephh static struct arrow *itree_add_arrow(struct node *apnode, 97*4436Sstephh struct node *fromevent, struct node *toevent, struct lut *ex); 98*4436Sstephh static struct event *find_or_add_event(struct info *infop, struct node *np); 99*4436Sstephh static void add_arrow(struct bubble *bp, struct arrow *ap); 1000Sstevel@tonic-gate static struct constraintlist *itree_add_constraint(struct arrow *arrowp, 1010Sstevel@tonic-gate struct node *c); 1020Sstevel@tonic-gate static struct bubble *itree_add_bubble(struct event *eventp, 1030Sstevel@tonic-gate enum bubbletype btype, int nork, int gen); 1040Sstevel@tonic-gate static void itree_free_bubble(struct bubble *freeme); 1050Sstevel@tonic-gate static void itree_free_constraints(struct arrow *ap); 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate /* 1080Sstevel@tonic-gate * the following struct contains the state we build up during 1090Sstevel@tonic-gate * vertical and horizontal expansion so that generate() 1100Sstevel@tonic-gate * has everything it needs to construct the appropriate arrows. 1110Sstevel@tonic-gate * after setting up the state by calling: 1120Sstevel@tonic-gate * generate_arrownp() 1130Sstevel@tonic-gate * generate_nork() 1140Sstevel@tonic-gate * generate_new() 1150Sstevel@tonic-gate * generate_from() 1160Sstevel@tonic-gate * generate_to() 1170Sstevel@tonic-gate * the actual arrow generation is done by calling: 1180Sstevel@tonic-gate * generate() 1190Sstevel@tonic-gate */ 1200Sstevel@tonic-gate static struct { 1210Sstevel@tonic-gate int generation; /* generation number of arrow set */ 1220Sstevel@tonic-gate struct node *arrownp; /* top-level parse tree for arrow */ 1230Sstevel@tonic-gate int n; /* n value associated with arrow */ 1240Sstevel@tonic-gate int k; /* k value associated with arrow */ 1250Sstevel@tonic-gate struct node *fromnp; /* left-hand-side event in parse tree */ 1260Sstevel@tonic-gate struct node *tonp; /* right-hand-side event in parse tree */ 1270Sstevel@tonic-gate struct event *frome; /* left-hand-side event in instance tree */ 1280Sstevel@tonic-gate struct event *toe; /* right-hand-side event in instance tree */ 1290Sstevel@tonic-gate struct bubble *frombp; /* bubble arrow comes from */ 1300Sstevel@tonic-gate struct bubble *tobp; /* bubble arrow goes to */ 1310Sstevel@tonic-gate } G; 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate static void 1340Sstevel@tonic-gate generate_arrownp(struct node *arrownp) 1350Sstevel@tonic-gate { 1360Sstevel@tonic-gate G.arrownp = arrownp; 1370Sstevel@tonic-gate } 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate static void 1400Sstevel@tonic-gate generate_nork(int n, int k) 1410Sstevel@tonic-gate { 1420Sstevel@tonic-gate G.n = n; 1430Sstevel@tonic-gate G.k = k; 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate static void 1470Sstevel@tonic-gate generate_new(void) 1480Sstevel@tonic-gate { 1490Sstevel@tonic-gate G.generation++; 1500Sstevel@tonic-gate } 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate static void 153*4436Sstephh generate_from(struct node *fromeventnp) 1540Sstevel@tonic-gate { 155*4436Sstephh G.frombp = NULL; 1560Sstevel@tonic-gate G.fromnp = fromeventnp; 1570Sstevel@tonic-gate } 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate static void 160*4436Sstephh generate_to(struct node *toeventnp) 1610Sstevel@tonic-gate { 1620Sstevel@tonic-gate G.tonp = toeventnp; 1630Sstevel@tonic-gate } 1640Sstevel@tonic-gate 1650Sstevel@tonic-gate static void 166*4436Sstephh generate(struct info *infop) 1670Sstevel@tonic-gate { 168*4436Sstephh struct arrow *arrowp; 169*4436Sstephh 1700Sstevel@tonic-gate ASSERT(G.arrownp != NULL); 1710Sstevel@tonic-gate ASSERT(G.fromnp != NULL); 1720Sstevel@tonic-gate ASSERT(G.tonp != NULL); 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate out(O_ALTFP|O_VERB3|O_NONL, " Arrow \""); 1750Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.fromnp); 1760Sstevel@tonic-gate out(O_ALTFP|O_VERB3|O_NONL, "\" -> \""); 1770Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, G.tonp); 178*4436Sstephh out(O_ALTFP|O_VERB3|O_NONL, "\" "); 1790Sstevel@tonic-gate 180*4436Sstephh arrowp = itree_add_arrow(G.arrownp, G.fromnp, G.tonp, infop->ex); 181*4436Sstephh if (arrowp == NULL) { 182*4436Sstephh out(O_ALTFP|O_VERB3, "(prevented by constraints)"); 1830Sstevel@tonic-gate } else { 184*4436Sstephh out(O_ALTFP|O_VERB3, ""); 185*4436Sstephh if (!G.frombp) { 186*4436Sstephh G.frome = find_or_add_event(infop, G.fromnp); 187*4436Sstephh G.frombp = itree_add_bubble(G.frome, B_FROM, G.n, 0); 188*4436Sstephh } 189*4436Sstephh G.toe = find_or_add_event(infop, G.tonp); 190*4436Sstephh G.tobp = itree_add_bubble(G.toe, B_TO, G.k, G.generation); 191*4436Sstephh arrowp->tail = G.frombp; 192*4436Sstephh arrowp->head = G.tobp; 193*4436Sstephh add_arrow(G.frombp, arrowp); 194*4436Sstephh add_arrow(G.tobp, arrowp); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate enum childnode_action { 1990Sstevel@tonic-gate CN_NONE, 2000Sstevel@tonic-gate CN_DUP 2010Sstevel@tonic-gate }; 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate static struct node * 2040Sstevel@tonic-gate tname_dup(struct node *namep, enum childnode_action act) 2050Sstevel@tonic-gate { 2060Sstevel@tonic-gate struct node *retp = NULL; 2070Sstevel@tonic-gate const char *file; 2080Sstevel@tonic-gate int line; 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate if (namep == NULL) 2110Sstevel@tonic-gate return (NULL); 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate file = namep->file; 2140Sstevel@tonic-gate line = namep->line; 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate for (; namep != NULL; namep = namep->u.name.next) { 2170Sstevel@tonic-gate struct node *newnp = newnode(T_NAME, file, line); 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate newnp->u.name.t = namep->u.name.t; 2200Sstevel@tonic-gate newnp->u.name.s = namep->u.name.s; 2210Sstevel@tonic-gate newnp->u.name.last = newnp; 2220Sstevel@tonic-gate newnp->u.name.it = namep->u.name.it; 2230Sstevel@tonic-gate newnp->u.name.cp = namep->u.name.cp; 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate if (act == CN_DUP) { 2260Sstevel@tonic-gate struct node *npc; 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate npc = namep->u.name.child; 2290Sstevel@tonic-gate if (npc != NULL) { 2300Sstevel@tonic-gate switch (npc->t) { 2310Sstevel@tonic-gate case T_NUM: 2320Sstevel@tonic-gate newnp->u.name.child = 233*4436Sstephh newnode(T_NUM, file, line); 2340Sstevel@tonic-gate newnp->u.name.child->u.ull = 235*4436Sstephh npc->u.ull; 2360Sstevel@tonic-gate break; 2370Sstevel@tonic-gate case T_NAME: 2380Sstevel@tonic-gate newnp->u.name.child = 239*4436Sstephh tree_name(npc->u.name.s, 240*4436Sstephh npc->u.name.it, file, line); 2410Sstevel@tonic-gate break; 2420Sstevel@tonic-gate default: 2430Sstevel@tonic-gate out(O_DIE, "tname_dup: " 2440Sstevel@tonic-gate "invalid child type %s", 2450Sstevel@tonic-gate ptree_nodetype2str(npc->t)); 2460Sstevel@tonic-gate } 2470Sstevel@tonic-gate } 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate if (retp == NULL) { 2510Sstevel@tonic-gate retp = newnp; 2520Sstevel@tonic-gate } else { 2530Sstevel@tonic-gate retp->u.name.last->u.name.next = newnp; 2540Sstevel@tonic-gate retp->u.name.last = newnp; 2550Sstevel@tonic-gate } 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate return (retp); 2590Sstevel@tonic-gate } 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate struct prop_wlk_data { 2620Sstevel@tonic-gate struct lut *props; 2630Sstevel@tonic-gate struct node *epname; 2640Sstevel@tonic-gate }; 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate static struct lut *props2instance(struct node *, struct node *); 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate /* 2690Sstevel@tonic-gate * let oldepname be a subset of epname. return the subsection of epname 2700Sstevel@tonic-gate * that ends with oldepname. make each component in the path explicitly 2710Sstevel@tonic-gate * instanced (i.e., with a T_NUM child). 2720Sstevel@tonic-gate */ 2730Sstevel@tonic-gate static struct node * 2740Sstevel@tonic-gate tname_dup_to_epname(struct node *oldepname, struct node *epname) 2750Sstevel@tonic-gate { 2760Sstevel@tonic-gate struct node *npref, *npend, *np1, *np2; 2770Sstevel@tonic-gate struct node *ret = NULL; 2780Sstevel@tonic-gate int foundmatch = 0; 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate if (epname == NULL) 2810Sstevel@tonic-gate return (NULL); 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate /* 2840Sstevel@tonic-gate * search for the longest path in epname which contains 2850Sstevel@tonic-gate * oldnode->u.event.epname. set npend to point to just past the 2860Sstevel@tonic-gate * end of this path. 2870Sstevel@tonic-gate */ 2880Sstevel@tonic-gate npend = NULL; 2890Sstevel@tonic-gate for (npref = epname; npref; npref = npref->u.name.next) { 2900Sstevel@tonic-gate if (npref->u.name.s == oldepname->u.name.s) { 2910Sstevel@tonic-gate for (np1 = npref, np2 = oldepname; 2920Sstevel@tonic-gate np1 != NULL && np2 != NULL; 2930Sstevel@tonic-gate np1 = np1->u.name.next, np2 = np2->u.name.next) { 2940Sstevel@tonic-gate if (np1->u.name.s != np2->u.name.s) 2950Sstevel@tonic-gate break; 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate if (np2 == NULL) { 2980Sstevel@tonic-gate foundmatch = 1; 2990Sstevel@tonic-gate npend = np1; 3000Sstevel@tonic-gate if (np1 == NULL) { 3010Sstevel@tonic-gate /* oldepname matched npref up to end */ 3020Sstevel@tonic-gate break; 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate } 3050Sstevel@tonic-gate } 3060Sstevel@tonic-gate } 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate if (foundmatch == 0) { 3090Sstevel@tonic-gate /* 3100Sstevel@tonic-gate * if oldepname could not be found in epname, return a 3110Sstevel@tonic-gate * duplicate of the former. do not try to instantize 3120Sstevel@tonic-gate * oldepname since it might not be a path. 3130Sstevel@tonic-gate */ 3140Sstevel@tonic-gate return (tname_dup(oldepname, CN_DUP)); 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate /* 3180Sstevel@tonic-gate * dup (epname -- npend). all children should be T_NUMs. 3190Sstevel@tonic-gate */ 3200Sstevel@tonic-gate for (npref = epname; 3210Sstevel@tonic-gate ! (npref == NULL || npref == npend); 3220Sstevel@tonic-gate npref = npref->u.name.next) { 3230Sstevel@tonic-gate struct node *newnp = newnode(T_NAME, oldepname->file, 324*4436Sstephh oldepname->line); 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate newnp->u.name.t = npref->u.name.t; 3270Sstevel@tonic-gate newnp->u.name.s = npref->u.name.s; 3280Sstevel@tonic-gate newnp->u.name.last = newnp; 3290Sstevel@tonic-gate newnp->u.name.it = npref->u.name.it; 3300Sstevel@tonic-gate newnp->u.name.cp = npref->u.name.cp; 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate newnp->u.name.child = newnode(T_NUM, oldepname->file, 333*4436Sstephh oldepname->line); 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate if (npref->u.name.child == NULL || 3360Sstevel@tonic-gate npref->u.name.child->t != T_NUM) { 3370Sstevel@tonic-gate int childnum; 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate ASSERT(npref->u.name.cp != NULL); 3400Sstevel@tonic-gate config_getcompname(npref->u.name.cp, NULL, &childnum); 3410Sstevel@tonic-gate newnp->u.name.child->u.ull = childnum; 3420Sstevel@tonic-gate } else { 3430Sstevel@tonic-gate newnp->u.name.child->u.ull = 344*4436Sstephh npref->u.name.child->u.ull; 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate if (ret == NULL) { 3480Sstevel@tonic-gate ret = newnp; 3490Sstevel@tonic-gate } else { 3500Sstevel@tonic-gate ret->u.name.last->u.name.next = newnp; 3510Sstevel@tonic-gate ret->u.name.last = newnp; 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate } 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate return (ret); 3560Sstevel@tonic-gate } 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate /* 3590Sstevel@tonic-gate * restriction: oldnode->u.event.epname has to be equivalent to or a subset 3600Sstevel@tonic-gate * of epname 3610Sstevel@tonic-gate */ 3620Sstevel@tonic-gate static struct node * 3630Sstevel@tonic-gate tevent_dup_to_epname(struct node *oldnode, struct node *epname) 3640Sstevel@tonic-gate { 3650Sstevel@tonic-gate struct node *ret; 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate ret = newnode(T_EVENT, oldnode->file, oldnode->line); 3680Sstevel@tonic-gate ret->u.event.ename = tname_dup(oldnode->u.event.ename, CN_NONE); 3690Sstevel@tonic-gate ret->u.event.epname = tname_dup_to_epname(oldnode->u.event.epname, 370*4436Sstephh epname); 3710Sstevel@tonic-gate return (ret); 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate static void 3750Sstevel@tonic-gate nv_instantiate(void *name, void *val, void *arg) 3760Sstevel@tonic-gate { 3770Sstevel@tonic-gate struct prop_wlk_data *pd = (struct prop_wlk_data *)arg; 3780Sstevel@tonic-gate struct node *orhs = (struct node *)val; 3790Sstevel@tonic-gate struct node *nrhs; 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate /* handle engines by instantizing the entire engine */ 3820Sstevel@tonic-gate if (name == L_engine) { 3830Sstevel@tonic-gate ASSERT(orhs->t == T_EVENT); 3840Sstevel@tonic-gate ASSERT(orhs->u.event.ename->u.name.t == N_SERD); 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate /* there are only SERD engines for now */ 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate nrhs = newnode(T_SERD, orhs->file, orhs->line); 3890Sstevel@tonic-gate nrhs->u.stmt.np = tevent_dup_to_epname(orhs, pd->epname); 3900Sstevel@tonic-gate nrhs->u.stmt.lutp = props2instance(orhs, pd->epname); 3910Sstevel@tonic-gate pd->props = lut_add(pd->props, name, nrhs, NULL); 3920Sstevel@tonic-gate return; 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate switch (orhs->t) { 3960Sstevel@tonic-gate case T_NUM: 3970Sstevel@tonic-gate nrhs = newnode(T_NUM, orhs->file, orhs->line); 3980Sstevel@tonic-gate nrhs->u.ull = orhs->u.ull; 3990Sstevel@tonic-gate pd->props = lut_add(pd->props, name, nrhs, NULL); 4000Sstevel@tonic-gate break; 4010Sstevel@tonic-gate case T_TIMEVAL: 4020Sstevel@tonic-gate nrhs = newnode(T_TIMEVAL, orhs->file, orhs->line); 4030Sstevel@tonic-gate nrhs->u.ull = orhs->u.ull; 4040Sstevel@tonic-gate pd->props = lut_add(pd->props, name, nrhs, NULL); 4050Sstevel@tonic-gate break; 4060Sstevel@tonic-gate case T_NAME: 4070Sstevel@tonic-gate nrhs = tname_dup_to_epname(orhs, pd->epname); 4080Sstevel@tonic-gate pd->props = lut_add(pd->props, name, nrhs, NULL); 4090Sstevel@tonic-gate break; 4100Sstevel@tonic-gate case T_EVENT: 4110Sstevel@tonic-gate nrhs = tevent_dup_to_epname(orhs, pd->epname); 4120Sstevel@tonic-gate pd->props = lut_add(pd->props, name, nrhs, NULL); 4130Sstevel@tonic-gate break; 4141414Scindi case T_GLOBID: 4151414Scindi nrhs = newnode(T_GLOBID, orhs->file, orhs->line); 4161414Scindi nrhs->u.globid.s = orhs->u.globid.s; 4171414Scindi pd->props = lut_add(pd->props, name, nrhs, NULL); 4181414Scindi break; 4191414Scindi case T_FUNC: 4201414Scindi /* for T_FUNC, we don't duplicate it, just point to node */ 4211414Scindi pd->props = lut_add(pd->props, name, orhs, NULL); 4221414Scindi break; 4230Sstevel@tonic-gate default: 4241414Scindi out(O_DIE, "unexpected nvpair value type %s", 4250Sstevel@tonic-gate ptree_nodetype2str(((struct node *)val)->t)); 4260Sstevel@tonic-gate } 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate static struct lut * 4300Sstevel@tonic-gate props2instance(struct node *eventnp, struct node *epname) 4310Sstevel@tonic-gate { 4320Sstevel@tonic-gate struct prop_wlk_data pd; 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate pd.props = NULL; 4350Sstevel@tonic-gate pd.epname = epname; 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate ASSERT(eventnp->u.event.declp != NULL); 4380Sstevel@tonic-gate lut_walk(eventnp->u.event.declp->u.stmt.lutp, nv_instantiate, &pd); 4390Sstevel@tonic-gate return (pd.props); 4400Sstevel@tonic-gate } 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate /*ARGSUSED*/ 4430Sstevel@tonic-gate static void 4440Sstevel@tonic-gate instances_destructor(void *left, void *right, void *arg) 4450Sstevel@tonic-gate { 4460Sstevel@tonic-gate struct node *dn = (struct node *)right; 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate if (dn->t == T_SERD) { 4490Sstevel@tonic-gate /* we allocated the lut during itree_create(), so free it */ 4500Sstevel@tonic-gate lut_free(dn->u.stmt.lutp, instances_destructor, NULL); 4510Sstevel@tonic-gate dn->u.stmt.lutp = NULL; 4520Sstevel@tonic-gate } 4531414Scindi if (dn->t != T_FUNC) /* T_FUNC pointed to original node */ 4541414Scindi tree_free(dn); 4551414Scindi } 4561414Scindi 4571414Scindi /*ARGSUSED*/ 4581414Scindi static void 4591414Scindi payloadprops_destructor(void *left, void *right, void *arg) 4601414Scindi { 4611414Scindi FREE(right); 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate /* 4650Sstevel@tonic-gate * event_cmp -- used via lut_lookup/lut_add on instance tree lut 4660Sstevel@tonic-gate */ 4670Sstevel@tonic-gate static int 4680Sstevel@tonic-gate event_cmp(struct event *ep1, struct event *ep2) 4690Sstevel@tonic-gate { 4700Sstevel@tonic-gate int diff; 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate if ((diff = ep2->enode->u.event.ename->u.name.s - 4730Sstevel@tonic-gate ep1->enode->u.event.ename->u.name.s) != 0) 4740Sstevel@tonic-gate return (diff); 4750Sstevel@tonic-gate if ((diff = (char *)ep2->ipp - (char *)ep1->ipp) != 0) 4760Sstevel@tonic-gate return (diff); 4770Sstevel@tonic-gate return (0); 4780Sstevel@tonic-gate 4790Sstevel@tonic-gate } 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate struct event * 4820Sstevel@tonic-gate itree_lookup(struct lut *itp, const char *ename, const struct ipath *ipp) 4830Sstevel@tonic-gate { 4840Sstevel@tonic-gate struct event searchevent; /* just used for searching */ 4850Sstevel@tonic-gate struct node searcheventnode; 4860Sstevel@tonic-gate struct node searchenamenode; 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate searchevent.enode = &searcheventnode; 4890Sstevel@tonic-gate searcheventnode.t = T_EVENT; 4900Sstevel@tonic-gate searcheventnode.u.event.ename = &searchenamenode; 4910Sstevel@tonic-gate searchenamenode.t = T_NAME; 4920Sstevel@tonic-gate searchenamenode.u.name.s = ename; 4930Sstevel@tonic-gate searchevent.ipp = ipp; 4940Sstevel@tonic-gate return (lut_lookup(itp, (void *)&searchevent, (lut_cmp)event_cmp)); 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate static struct event * 4980Sstevel@tonic-gate find_or_add_event(struct info *infop, struct node *np) 4990Sstevel@tonic-gate { 5000Sstevel@tonic-gate struct event *ret; 5010Sstevel@tonic-gate struct event searchevent; /* just used for searching */ 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate ASSERTeq(np->t, T_EVENT, ptree_nodetype2str); 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate searchevent.enode = np; 5060Sstevel@tonic-gate searchevent.ipp = ipath(np->u.event.epname); 5070Sstevel@tonic-gate if ((ret = lut_lookup(infop->lut, (void *)&searchevent, 5080Sstevel@tonic-gate (lut_cmp)event_cmp)) != NULL) 5090Sstevel@tonic-gate return (ret); 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate /* wasn't already in tree, allocate it */ 512*4436Sstephh ret = alloc_xmalloc(sizeof (*ret)); 5130Sstevel@tonic-gate bzero(ret, sizeof (*ret)); 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate ret->t = np->u.event.ename->u.name.t; 5160Sstevel@tonic-gate ret->enode = np; 5170Sstevel@tonic-gate ret->ipp = searchevent.ipp; 5180Sstevel@tonic-gate ret->props = props2instance(np, np->u.event.epname); 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate infop->lut = lut_add(infop->lut, (void *)ret, (void *)ret, 5210Sstevel@tonic-gate (lut_cmp)event_cmp); 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate return (ret); 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate /* 5270Sstevel@tonic-gate * hmatch_event -- perform any appropriate horizontal expansion on an event 5280Sstevel@tonic-gate * 5290Sstevel@tonic-gate * this routine is used to perform horizontal expansion on both the 5300Sstevel@tonic-gate * left-hand-side events in a prop, and the right-hand-side events. 5310Sstevel@tonic-gate * when called to handle a left-side event, nextnp point to the right 5320Sstevel@tonic-gate * side of the prop that should be passed to hmatch() for each match 5330Sstevel@tonic-gate * found by horizontal expansion. when no horizontal expansion exists, 5340Sstevel@tonic-gate * we will still "match" one event for every event found in the list on 5350Sstevel@tonic-gate * the left-hand-side of the prop because vmatch() already found that 5360Sstevel@tonic-gate * there's at least one match during vertical expansion. 5370Sstevel@tonic-gate */ 5380Sstevel@tonic-gate static void 5390Sstevel@tonic-gate hmatch_event(struct info *infop, struct node *eventnp, struct node *epname, 5400Sstevel@tonic-gate struct config *ncp, struct node *nextnp, int rematch) 5410Sstevel@tonic-gate { 5420Sstevel@tonic-gate if (epname == NULL) { 5430Sstevel@tonic-gate /* 5440Sstevel@tonic-gate * end of pathname recursion, either we just located 5450Sstevel@tonic-gate * a left-hand-side event and we're ready to move on 5460Sstevel@tonic-gate * to the expanding the right-hand-side events, or 5470Sstevel@tonic-gate * we're further down the recursion and we just located 5480Sstevel@tonic-gate * a right-hand-side event. the passed-in parameter 5490Sstevel@tonic-gate * "nextnp" tells us whether we're working on the left 5500Sstevel@tonic-gate * side and need to move on to nextnp, or if nextnp is 5510Sstevel@tonic-gate * NULL, we're working on the right side. 5520Sstevel@tonic-gate */ 5530Sstevel@tonic-gate if (nextnp) { 5540Sstevel@tonic-gate /* 5550Sstevel@tonic-gate * finished a left side expansion, move on to right. 5560Sstevel@tonic-gate * tell generate() what event we just matched so 5570Sstevel@tonic-gate * it can be used at the source of any arrows 5580Sstevel@tonic-gate * we generate as we match events on the right side. 5590Sstevel@tonic-gate */ 560*4436Sstephh generate_from(eventnp); 5610Sstevel@tonic-gate hmatch(infop, nextnp, NULL); 5620Sstevel@tonic-gate } else { 5630Sstevel@tonic-gate /* 5640Sstevel@tonic-gate * finished a right side expansion. tell generate 5650Sstevel@tonic-gate * the information about the destination and let 5660Sstevel@tonic-gate * it construct the arrows as appropriate. 5670Sstevel@tonic-gate */ 568*4436Sstephh generate_to(eventnp); 569*4436Sstephh generate(infop); 5700Sstevel@tonic-gate } 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate return; 5730Sstevel@tonic-gate } 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate ASSERTeq(epname->t, T_NAME, ptree_nodetype2str); 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate /* 5780Sstevel@tonic-gate * we only get here when eventnp already has a completely 5790Sstevel@tonic-gate * instanced epname in it already. so we first recurse 5800Sstevel@tonic-gate * down to the end of the name and as the recursion pops 5810Sstevel@tonic-gate * up, we look for opportunities to advance horizontal 582*4436Sstephh * expansions on to the next match. 5830Sstevel@tonic-gate */ 584*4436Sstephh if (epname->u.name.it == IT_HORIZONTAL || rematch) { 5850Sstevel@tonic-gate struct config *cp; 5860Sstevel@tonic-gate struct config *ocp = epname->u.name.cp; 5870Sstevel@tonic-gate char *cp_s; 5880Sstevel@tonic-gate int cp_num; 5890Sstevel@tonic-gate int ocp_num; 5900Sstevel@tonic-gate struct iterinfo *iterinfop = NULL; 5910Sstevel@tonic-gate const char *iters; 592*4436Sstephh int hexpand = 0; 5930Sstevel@tonic-gate 594*4436Sstephh if (epname->u.name.it != IT_HORIZONTAL) { 595*4436Sstephh /* 596*4436Sstephh * Ancestor was horizontal though, so must rematch 597*4436Sstephh * against the name/num found in vmatch. 598*4436Sstephh */ 599*4436Sstephh config_getcompname(ocp, NULL, &ocp_num); 600*4436Sstephh } else { 601*4436Sstephh iters = epname->u.name.child->u.name.s; 602*4436Sstephh if ((iterinfop = lut_lookup(infop->ex, 603*4436Sstephh (void *)iters, NULL)) == NULL) { 604*4436Sstephh /* 605*4436Sstephh * do horizontal expansion on this node 606*4436Sstephh */ 607*4436Sstephh hexpand = 1; 608*4436Sstephh iterinfop = alloc_xmalloc( 609*4436Sstephh sizeof (struct iterinfo)); 610*4436Sstephh iterinfop->num = -1; 611*4436Sstephh iterinfop->np = epname; 612*4436Sstephh infop->ex = lut_add(infop->ex, (void *)iters, 613*4436Sstephh iterinfop, NULL); 614*4436Sstephh } else if (iterinfop->num == -1) { 615*4436Sstephh hexpand = 1; 616*4436Sstephh } else { 617*4436Sstephh /* 618*4436Sstephh * This name has already been used in a 619*4436Sstephh * horizontal expansion. This time just match it 620*4436Sstephh */ 621*4436Sstephh ocp_num = iterinfop->num; 622*4436Sstephh } 623*4436Sstephh } 624*4436Sstephh /* 625*4436Sstephh * Run through siblings looking for any that match the name. 626*4436Sstephh * If hexpand not set then num must also match ocp_num. 627*4436Sstephh */ 628*4436Sstephh for (cp = rematch ? ncp : ocp; cp; cp = config_next(cp)) { 629*4436Sstephh config_getcompname(cp, &cp_s, &cp_num); 630*4436Sstephh if (cp_s == epname->u.name.s) { 631*4436Sstephh if (hexpand) 6320Sstevel@tonic-gate iterinfop->num = cp_num; 633*4436Sstephh else if (ocp_num != cp_num) 634*4436Sstephh continue; 6350Sstevel@tonic-gate epname->u.name.cp = cp; 6360Sstevel@tonic-gate hmatch_event(infop, eventnp, 6370Sstevel@tonic-gate epname->u.name.next, config_child(cp), 6380Sstevel@tonic-gate nextnp, 1); 6390Sstevel@tonic-gate } 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate epname->u.name.cp = ocp; 642*4436Sstephh if (hexpand) 643*4436Sstephh iterinfop->num = -1; 644*4436Sstephh } else { 645*4436Sstephh hmatch_event(infop, eventnp, epname->u.name.next, 646*4436Sstephh NULL, nextnp, 0); 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate } 6490Sstevel@tonic-gate 6500Sstevel@tonic-gate /* 6510Sstevel@tonic-gate * hmatch -- check for horizontal expansion matches 6520Sstevel@tonic-gate * 6530Sstevel@tonic-gate * np points to the things we're matching (like a T_LIST or a T_EVENT) 6540Sstevel@tonic-gate * and if we're working on a left-side of a prop, nextnp points to 6550Sstevel@tonic-gate * the other side of the prop that we'll tackle next when this recursion 6560Sstevel@tonic-gate * bottoms out. when all the events in the entire prop arrow have been 6570Sstevel@tonic-gate * horizontally expanded, generate() will be called to generate the 6580Sstevel@tonic-gate * actualy arrow. 6590Sstevel@tonic-gate */ 6600Sstevel@tonic-gate static void 6610Sstevel@tonic-gate hmatch(struct info *infop, struct node *np, struct node *nextnp) 6620Sstevel@tonic-gate { 6630Sstevel@tonic-gate if (np == NULL) 6640Sstevel@tonic-gate return; /* all done */ 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate /* 6670Sstevel@tonic-gate * for each item in the list of events (which could just 6680Sstevel@tonic-gate * be a single event, or it could get larger in the loop 6690Sstevel@tonic-gate * below due to horizontal expansion), call hmatch on 6700Sstevel@tonic-gate * the right side and create arrows to each element. 6710Sstevel@tonic-gate */ 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate switch (np->t) { 6740Sstevel@tonic-gate case T_LIST: 6750Sstevel@tonic-gate /* loop through the list */ 6760Sstevel@tonic-gate if (np->u.expr.left) 6770Sstevel@tonic-gate hmatch(infop, np->u.expr.left, nextnp); 6780Sstevel@tonic-gate if (np->u.expr.right) 6790Sstevel@tonic-gate hmatch(infop, np->u.expr.right, nextnp); 6800Sstevel@tonic-gate break; 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate case T_EVENT: 6830Sstevel@tonic-gate hmatch_event(infop, np, np->u.event.epname, 6840Sstevel@tonic-gate NULL, nextnp, 0); 6850Sstevel@tonic-gate break; 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate default: 6880Sstevel@tonic-gate outfl(O_DIE, np->file, np->line, 6890Sstevel@tonic-gate "hmatch: unexpected type: %s", 6900Sstevel@tonic-gate ptree_nodetype2str(np->t)); 6910Sstevel@tonic-gate } 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate static int 6950Sstevel@tonic-gate itree_np2nork(struct node *norknp) 6960Sstevel@tonic-gate { 6970Sstevel@tonic-gate if (norknp == NULL) 6980Sstevel@tonic-gate return (1); 6990Sstevel@tonic-gate else if (norknp->t == T_NAME && norknp->u.name.s == L_A) 7000Sstevel@tonic-gate return (-1); /* our internal version of "all" */ 7010Sstevel@tonic-gate else if (norknp->t == T_NUM) 7020Sstevel@tonic-gate return ((int)norknp->u.ull); 7030Sstevel@tonic-gate else 704*4436Sstephh outfl(O_DIE, norknp->file, norknp->line, 7050Sstevel@tonic-gate "itree_np2nork: internal error type %s", 7060Sstevel@tonic-gate ptree_nodetype2str(norknp->t)); 7070Sstevel@tonic-gate /*NOTREACHED*/ 7081717Swesolows return (1); 7090Sstevel@tonic-gate } 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate static struct iterinfo * 7120Sstevel@tonic-gate newiterinfo(int num, struct node *np) 7130Sstevel@tonic-gate { 714*4436Sstephh struct iterinfo *ret = alloc_xmalloc(sizeof (*ret)); 7150Sstevel@tonic-gate 7160Sstevel@tonic-gate ret->num = num; 7170Sstevel@tonic-gate ret->np = np; 7180Sstevel@tonic-gate return (ret); 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate /*ARGSUSED*/ 7220Sstevel@tonic-gate static void 7230Sstevel@tonic-gate iterinfo_destructor(void *left, void *right, void *arg) 7240Sstevel@tonic-gate { 7250Sstevel@tonic-gate struct iterinfo *iterinfop = (struct iterinfo *)right; 7260Sstevel@tonic-gate 727*4436Sstephh alloc_xfree(iterinfop, sizeof (*iterinfop)); 7280Sstevel@tonic-gate } 7290Sstevel@tonic-gate 730*4436Sstephh static void 731*4436Sstephh vmatch_event(struct info *infop, struct config *cp, struct node *np, 732*4436Sstephh struct node *lnp, struct node *anp, struct wildcardinfo *wcp) 733186Sdb35262 { 734*4436Sstephh char *cp_s; 735*4436Sstephh int cp_num; 736*4436Sstephh struct node *ewlp, *ewfp; 737*4436Sstephh struct config *pcp; 738*4436Sstephh struct node *cpnode; 739*4436Sstephh int newewname = 0; 740186Sdb35262 741*4436Sstephh if (np == NULL) { 742186Sdb35262 /* 743*4436Sstephh * Reached the end of the name. u.name.cp pointers should be set 744*4436Sstephh * up for each part of name. From this we can use config tree 745*4436Sstephh * to build up the wildcard part of the name (if any). 746186Sdb35262 */ 747*4436Sstephh pcp = config_parent(wcp->nptop->u.event.epname->u.name.cp); 748*4436Sstephh if (pcp == infop->croot) { 749*4436Sstephh /* 750*4436Sstephh * no wildcarding done - move on to next entry 751*4436Sstephh */ 752*4436Sstephh wcp->nptop->u.event.ewname = wcp->ewname; 753*4436Sstephh wcp->nptop->u.event.oldepname = wcp->oldepname; 754*4436Sstephh vmatch(infop, np, lnp, anp); 755*4436Sstephh return; 756*4436Sstephh } 757*4436Sstephh if (wcp->ewname == NULL) { 758*4436Sstephh /* 759*4436Sstephh * ewname not yet set up - do it now 760*4436Sstephh */ 761*4436Sstephh newewname = 1; 762*4436Sstephh for (; pcp != infop->croot; pcp = config_parent(pcp)) { 763*4436Sstephh config_getcompname(pcp, &cp_s, &cp_num); 764*4436Sstephh cpnode = tree_name(cp_s, IT_NONE, NULL, 0); 765*4436Sstephh cpnode->u.name.child = newnode(T_NUM, NULL, 0); 766*4436Sstephh cpnode->u.name.child->u.ull = cp_num; 767*4436Sstephh cpnode->u.name.cp = pcp; 768*4436Sstephh if (wcp->ewname != NULL) { 769*4436Sstephh cpnode->u.name.next = wcp->ewname; 770*4436Sstephh cpnode->u.name.last = 771*4436Sstephh wcp->ewname->u.name.last; 772*4436Sstephh } 773*4436Sstephh wcp->ewname = cpnode; 774*4436Sstephh } 775*4436Sstephh } 776186Sdb35262 777186Sdb35262 /* 778*4436Sstephh * dup ewname and append oldepname 779186Sdb35262 */ 780*4436Sstephh ewfp = tname_dup(wcp->ewname, CN_DUP); 781*4436Sstephh ewlp = ewfp->u.name.last; 782*4436Sstephh ewfp->u.name.last = wcp->oldepname->u.name.last; 783*4436Sstephh ewlp->u.name.next = wcp->oldepname; 784*4436Sstephh 785*4436Sstephh wcp->nptop->u.event.epname = ewfp; 786*4436Sstephh wcp->nptop->u.event.ewname = wcp->ewname; 787*4436Sstephh wcp->nptop->u.event.oldepname = wcp->oldepname; 788*4436Sstephh vmatch(infop, np, lnp, anp); 789*4436Sstephh wcp->nptop->u.event.epname = wcp->oldepname; 790186Sdb35262 791*4436Sstephh /* 792*4436Sstephh * reduce duped ewname to original then free 793*4436Sstephh */ 794*4436Sstephh ewlp->u.name.next = NULL; 795*4436Sstephh ewfp->u.name.last = ewlp; 796*4436Sstephh tree_free(ewfp); 797186Sdb35262 798*4436Sstephh if (newewname) { 799*4436Sstephh /* 800*4436Sstephh * free ewname if allocated above 801*4436Sstephh */ 802*4436Sstephh tree_free(wcp->ewname); 803*4436Sstephh wcp->ewname = NULL; 804*4436Sstephh } 805*4436Sstephh return; 806186Sdb35262 } 807186Sdb35262 808186Sdb35262 /* 809*4436Sstephh * We have an np. See if we can match it in this section of 810*4436Sstephh * the config tree. 8110Sstevel@tonic-gate */ 8120Sstevel@tonic-gate if (cp == NULL) 8130Sstevel@tonic-gate return; /* no more config to match against */ 8140Sstevel@tonic-gate 8150Sstevel@tonic-gate for (; cp; cp = config_next(cp)) { 8160Sstevel@tonic-gate config_getcompname(cp, &cp_s, &cp_num); 8170Sstevel@tonic-gate 818*4436Sstephh if (cp_s == np->u.name.s) { 8190Sstevel@tonic-gate /* found a matching component name */ 8200Sstevel@tonic-gate if (np->u.name.child && 8210Sstevel@tonic-gate np->u.name.child->t == T_NUM) { 8220Sstevel@tonic-gate /* 8230Sstevel@tonic-gate * an explicit instance number was given 8240Sstevel@tonic-gate * in the source. so only consider this 8250Sstevel@tonic-gate * a configuration match if the number 8260Sstevel@tonic-gate * also matches. 8270Sstevel@tonic-gate */ 8280Sstevel@tonic-gate if (cp_num != np->u.name.child->u.ull) 8290Sstevel@tonic-gate continue; 8300Sstevel@tonic-gate 831*4436Sstephh } else if (np->u.name.it != IT_HORIZONTAL) { 8320Sstevel@tonic-gate struct iterinfo *iterinfop; 8330Sstevel@tonic-gate const char *iters; 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate /* 8360Sstevel@tonic-gate * vertical iterator. look it up in 8370Sstevel@tonic-gate * the appropriate lut and if we get 8380Sstevel@tonic-gate * back a value it is either one that we 8390Sstevel@tonic-gate * set earlier, in which case we record 8400Sstevel@tonic-gate * the new value for this iteration and 8410Sstevel@tonic-gate * keep matching, or it is one that was 8420Sstevel@tonic-gate * set by an earlier reference to the 8430Sstevel@tonic-gate * iterator, in which case we only consider 8440Sstevel@tonic-gate * this a configuration match if the number 8450Sstevel@tonic-gate * matches cp_num. 8460Sstevel@tonic-gate */ 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate ASSERT(np->u.name.child != NULL); 8490Sstevel@tonic-gate ASSERT(np->u.name.child->t == T_NAME); 8500Sstevel@tonic-gate iters = np->u.name.child->u.name.s; 8510Sstevel@tonic-gate 8520Sstevel@tonic-gate if ((iterinfop = lut_lookup(infop->ex, 8530Sstevel@tonic-gate (void *)iters, NULL)) == NULL) { 8540Sstevel@tonic-gate /* we're the first use, record our np */ 8550Sstevel@tonic-gate infop->ex = lut_add(infop->ex, 8560Sstevel@tonic-gate (void *)iters, 8570Sstevel@tonic-gate newiterinfo(cp_num, np), NULL); 8580Sstevel@tonic-gate } else if (np == iterinfop->np) { 8590Sstevel@tonic-gate /* 8600Sstevel@tonic-gate * we're the first use, back again 8610Sstevel@tonic-gate * for another iteration. so update 8620Sstevel@tonic-gate * the num bound to this iterator in 8630Sstevel@tonic-gate * the lut. 8640Sstevel@tonic-gate */ 8650Sstevel@tonic-gate iterinfop->num = cp_num; 8660Sstevel@tonic-gate } else if (cp_num != iterinfop->num) { 8670Sstevel@tonic-gate /* 8680Sstevel@tonic-gate * an earlier reference to this 8690Sstevel@tonic-gate * iterator bound it to a different 8700Sstevel@tonic-gate * instance number, so there's no 8710Sstevel@tonic-gate * match here after all. 872186Sdb35262 * 873186Sdb35262 * however, it's possible that this 874186Sdb35262 * component should really be part of 875186Sdb35262 * the wildcard. we explore this by 876186Sdb35262 * forcing this component into the 877186Sdb35262 * wildcarded section. 878186Sdb35262 * 879186Sdb35262 * for an more details of what's 880186Sdb35262 * going to happen now, see 881186Sdb35262 * comments block below entitled 882186Sdb35262 * "forcing components into 883186Sdb35262 * wildcard path". 8840Sstevel@tonic-gate */ 885*4436Sstephh if (np == wcp->nptop->u.event.epname) 886*4436Sstephh vmatch_event(infop, 887*4436Sstephh config_child(cp), np, lnp, 888*4436Sstephh anp, wcp); 8890Sstevel@tonic-gate continue; 8900Sstevel@tonic-gate } 8910Sstevel@tonic-gate } 8920Sstevel@tonic-gate 8930Sstevel@tonic-gate /* 894*4436Sstephh * if this was an IT_HORIZONTAL name, hmatch() will 895*4436Sstephh * expand all matches horizontally into a list. 8960Sstevel@tonic-gate * we know the list will contain at least 8970Sstevel@tonic-gate * one element (the one we just matched), 898*4436Sstephh * so we just let hmatch_event() do the rest. 8990Sstevel@tonic-gate * 900*4436Sstephh * recurse on to next component. Note that 9010Sstevel@tonic-gate * wildcarding is now turned off. 9020Sstevel@tonic-gate */ 903*4436Sstephh np->u.name.cp = cp; 9040Sstevel@tonic-gate vmatch_event(infop, config_child(cp), np->u.name.next, 905*4436Sstephh lnp, anp, wcp); 906*4436Sstephh np->u.name.cp = NULL; 9070Sstevel@tonic-gate 9080Sstevel@tonic-gate /* 909186Sdb35262 * forcing components into wildcard path: 910186Sdb35262 * 911186Sdb35262 * if this component is the first match, force it 912186Sdb35262 * to be part of the wildcarded path and see if we 913*4436Sstephh * can get additional matches. 914186Sdb35262 * 915186Sdb35262 * here's an example. suppose we have the 916186Sdb35262 * definition 917186Sdb35262 * event foo@x/y 918186Sdb35262 * and configuration 919186Sdb35262 * a0/x0/y0/a1/x1/y1 920186Sdb35262 * 921186Sdb35262 * the code up to this point will treat "a0" as the 922186Sdb35262 * wildcarded part of the path and "x0/y0" as the 923186Sdb35262 * nonwildcarded part, resulting in the instanced 924186Sdb35262 * event 925186Sdb35262 * foo@a0/x0/y0 926186Sdb35262 * 927186Sdb35262 * in order to discover the next match (.../x1/y1) 928186Sdb35262 * in the configuration we have to force "x0" into 929*4436Sstephh * the wildcarded part of the path. 930186Sdb35262 * by doing so, we discover the wildcarded part 931186Sdb35262 * "a0/x0/y0/a1" and the nonwildcarded part "x1/y1" 932186Sdb35262 * 933186Sdb35262 * the following call to vmatch_event() is also 934186Sdb35262 * needed to properly handle the configuration 935186Sdb35262 * b0/x0/b1/x1/y1 936186Sdb35262 * 937186Sdb35262 * the recursions into vmatch_event() will start 938186Sdb35262 * off uncovering "b0" as the wildcarded part and 939186Sdb35262 * "x0" as the start of the nonwildcarded path. 940186Sdb35262 * however, the next recursion will not result in a 941186Sdb35262 * match since there is no "y" following "x0". the 942186Sdb35262 * subsequent match of (wildcard = "b0/x0/b1" and 943186Sdb35262 * nonwildcard = "x1/y1") will be discovered only 944186Sdb35262 * if "x0" is forced to be a part of the wildcarded 945186Sdb35262 * path. 9460Sstevel@tonic-gate */ 947*4436Sstephh if (np == wcp->nptop->u.event.epname) 948*4436Sstephh vmatch_event(infop, config_child(cp), np, lnp, 949*4436Sstephh anp, wcp); 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate if (np->u.name.it == IT_HORIZONTAL) { 9520Sstevel@tonic-gate /* 9530Sstevel@tonic-gate * hmatch() finished iterating through 9540Sstevel@tonic-gate * the configuration as described above, so 9550Sstevel@tonic-gate * don't continue iterating here. 9560Sstevel@tonic-gate */ 9570Sstevel@tonic-gate return; 9580Sstevel@tonic-gate } 959*4436Sstephh } else if (np == wcp->nptop->u.event.epname) { 9600Sstevel@tonic-gate /* 961*4436Sstephh * no match - carry on down the tree looking for 962*4436Sstephh * wildcarding 9630Sstevel@tonic-gate */ 9640Sstevel@tonic-gate vmatch_event(infop, config_child(cp), np, lnp, anp, 965*4436Sstephh wcp); 9660Sstevel@tonic-gate } 9670Sstevel@tonic-gate } 9680Sstevel@tonic-gate } 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate /* 9710Sstevel@tonic-gate * vmatch -- find the next vertical expansion match in the config database 9720Sstevel@tonic-gate * 9730Sstevel@tonic-gate * this routine is called with three node pointers: 9740Sstevel@tonic-gate * np -- the parse we're matching 9750Sstevel@tonic-gate * lnp -- the rest of the list we're currently working on 9760Sstevel@tonic-gate * anp -- the rest of the arrow we're currently working on 9770Sstevel@tonic-gate * 9780Sstevel@tonic-gate * the expansion matching happens via three types of recursion: 9790Sstevel@tonic-gate * 9800Sstevel@tonic-gate * - when given an arrow, handle the left-side and then recursively 9810Sstevel@tonic-gate * handle the right side (which might be another cascaded arrow). 9820Sstevel@tonic-gate * 9830Sstevel@tonic-gate * - when handling one side of an arrow, recurse through the T_LIST 9840Sstevel@tonic-gate * to get to each event (or just move on to the event if there 9850Sstevel@tonic-gate * is a single event instead of a list) since the arrow parse 9860Sstevel@tonic-gate * trees recurse left, we actually start with the right-most 9870Sstevel@tonic-gate * event list in the prop statement and work our way towards 9880Sstevel@tonic-gate * the left-most event list. 9890Sstevel@tonic-gate * 9900Sstevel@tonic-gate * - when handling an event, recurse down each component of the 9910Sstevel@tonic-gate * pathname, matching in the config database and recording the 9920Sstevel@tonic-gate * matches in the explicit iterator dictionary as we go. 9930Sstevel@tonic-gate * 9940Sstevel@tonic-gate * when the bottom of this matching recursion is met, meaning we have 9950Sstevel@tonic-gate * set the "cp" pointers on all the names in the entire statement, 9960Sstevel@tonic-gate * we call hmatch() which does it's own recursion to handle horizontal 9970Sstevel@tonic-gate * expandsion and then call generate() to generate nodes, bubbles, and 9980Sstevel@tonic-gate * arrows in the instance tree. generate() looks at the cp pointers to 9990Sstevel@tonic-gate * see what instance numbers were matched in the configuration database. 10000Sstevel@tonic-gate * 10010Sstevel@tonic-gate * when horizontal expansion appears, vmatch() finds only the first match 10020Sstevel@tonic-gate * and hmatch() then takes the horizontal expansion through all the other 10030Sstevel@tonic-gate * matches when generating the arrows in the instance tree. 10040Sstevel@tonic-gate * 10050Sstevel@tonic-gate * the "infop" passed down through the recursion contains a dictionary 10060Sstevel@tonic-gate * of the explicit iterators (all the implicit iterators have been converted 10070Sstevel@tonic-gate * to explicit iterators when the parse tree was created by tree.c), which 10080Sstevel@tonic-gate * allows things like this to work correctly: 10090Sstevel@tonic-gate * 10100Sstevel@tonic-gate * prop error.a@x[n]/y/z -> error.b@x/y[n]/z -> error.c@x/y/z[n]; 10110Sstevel@tonic-gate * 10120Sstevel@tonic-gate * during the top level call, the explicit iterator "n" will match an 10130Sstevel@tonic-gate * instance number in the config database, and the result will be recorded 10140Sstevel@tonic-gate * in the explicit iterator dictionary and passed down via "infop". so 10150Sstevel@tonic-gate * when the recursive call tries to match y[n] in the config database, it 10160Sstevel@tonic-gate * will only match the same instance number as x[n] did since the dictionary 10170Sstevel@tonic-gate * is consulted to see if "n" took on a value already. 10180Sstevel@tonic-gate * 10190Sstevel@tonic-gate * at any point during the recursion, match*() can return to indicate 10200Sstevel@tonic-gate * a match was not found in the config database and that the caller should 10210Sstevel@tonic-gate * move on to the next potential match, if any. 10220Sstevel@tonic-gate * 10230Sstevel@tonic-gate * constraints are completely ignored by match(), so the statement: 10240Sstevel@tonic-gate * 10250Sstevel@tonic-gate * prop error.a@x[n] -> error.b@x[n] {n != 0}; 10260Sstevel@tonic-gate * 10270Sstevel@tonic-gate * might very well match x[0] if it appears in the config database. it 10280Sstevel@tonic-gate * is the generate() routine that takes that match and then decides what 10290Sstevel@tonic-gate * arrow, if any, should be generated in the instance tree. generate() 10300Sstevel@tonic-gate * looks at the explicit iterator dictionary to get values like "n" in 10310Sstevel@tonic-gate * the above example so that it can evaluate constraints. 10320Sstevel@tonic-gate * 10330Sstevel@tonic-gate */ 10340Sstevel@tonic-gate static void 1035*4436Sstephh vmatch(struct info *infop, struct node *np, struct node *lnp, struct node *anp) 10360Sstevel@tonic-gate { 1037*4436Sstephh struct node *np1, *np2, *oldepname, *oldnptop; 1038*4436Sstephh int epmatches; 1039*4436Sstephh struct config *cp; 1040*4436Sstephh struct wildcardinfo *wcp; 1041*4436Sstephh 10420Sstevel@tonic-gate if (np == NULL) { 10430Sstevel@tonic-gate if (lnp) 1044*4436Sstephh vmatch(infop, lnp, NULL, anp); 10450Sstevel@tonic-gate else if (anp) 1046*4436Sstephh vmatch(infop, anp, NULL, NULL); 10470Sstevel@tonic-gate else { 10480Sstevel@tonic-gate struct node *src; 10490Sstevel@tonic-gate struct node *dst; 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate /* end of vertical match recursion */ 10520Sstevel@tonic-gate outfl(O_ALTFP|O_VERB3|O_NONL, 10530Sstevel@tonic-gate infop->anp->file, infop->anp->line, "vmatch: "); 10540Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, infop->anp); 10550Sstevel@tonic-gate out(O_ALTFP|O_VERB3, NULL); 10560Sstevel@tonic-gate 10570Sstevel@tonic-gate generate_nork( 10580Sstevel@tonic-gate itree_np2nork(infop->anp->u.arrow.nnp), 10590Sstevel@tonic-gate itree_np2nork(infop->anp->u.arrow.knp)); 10600Sstevel@tonic-gate dst = infop->anp->u.arrow.rhs; 10610Sstevel@tonic-gate src = infop->anp->u.arrow.lhs; 10620Sstevel@tonic-gate for (;;) { 10630Sstevel@tonic-gate generate_new(); /* new set of arrows */ 10640Sstevel@tonic-gate if (src->t == T_ARROW) { 10650Sstevel@tonic-gate hmatch(infop, src->u.arrow.rhs, dst); 10660Sstevel@tonic-gate generate_nork( 10670Sstevel@tonic-gate itree_np2nork(src->u.arrow.nnp), 10680Sstevel@tonic-gate itree_np2nork(src->u.arrow.knp)); 10690Sstevel@tonic-gate dst = src->u.arrow.rhs; 10700Sstevel@tonic-gate src = src->u.arrow.lhs; 10710Sstevel@tonic-gate } else { 10720Sstevel@tonic-gate hmatch(infop, src, dst); 10730Sstevel@tonic-gate break; 10740Sstevel@tonic-gate } 10750Sstevel@tonic-gate } 10760Sstevel@tonic-gate } 10770Sstevel@tonic-gate return; 10780Sstevel@tonic-gate } 10790Sstevel@tonic-gate 10800Sstevel@tonic-gate switch (np->t) { 10810Sstevel@tonic-gate case T_EVENT: { 1082*4436Sstephh epmatches = 0; 1083*4436Sstephh /* 1084*4436Sstephh * see if we already have a match in the wcps 1085*4436Sstephh */ 1086*4436Sstephh for (wcp = wcproot; wcp; wcp = wcp->next) { 1087*4436Sstephh oldepname = wcp->oldepname; 1088*4436Sstephh oldnptop = wcp->nptop; 1089*4436Sstephh for (np1 = oldepname, np2 = np->u.event.epname; 1090*4436Sstephh np1 != NULL && np2 != NULL; np1 = np1->u.name.next, 1091*4436Sstephh np2 = np2->u.name.next) { 1092*4436Sstephh if (strcmp(np1->u.name.s, np2->u.name.s) != 0) 1093*4436Sstephh break; 1094*4436Sstephh if (np1->u.name.child->t != 1095*4436Sstephh np2->u.name.child->t) 1096*4436Sstephh break; 1097*4436Sstephh if (np1->u.name.child->t == T_NUM && 1098*4436Sstephh np1->u.name.child->u.ull != 1099*4436Sstephh np2->u.name.child->u.ull) 1100*4436Sstephh break; 1101*4436Sstephh if (np1->u.name.child->t == T_NAME && 1102*4436Sstephh strcmp(np1->u.name.child->u.name.s, 1103*4436Sstephh np2->u.name.child->u.name.s) != 0) 1104*4436Sstephh break; 1105*4436Sstephh epmatches++; 1106*4436Sstephh } 1107*4436Sstephh if (epmatches) 1108*4436Sstephh break; 1109*4436Sstephh } 1110*4436Sstephh if (epmatches && np1 == NULL && np2 == NULL) { 1111*4436Sstephh /* 1112*4436Sstephh * complete names match, can just borrow the fields 1113*4436Sstephh */ 1114*4436Sstephh oldepname = np->u.event.epname; 1115*4436Sstephh np->u.event.epname = oldnptop->u.event.epname; 1116*4436Sstephh np->u.event.oldepname = wcp->oldepname; 1117*4436Sstephh np->u.event.ewname = wcp->ewname; 1118*4436Sstephh vmatch(infop, NULL, lnp, anp); 1119*4436Sstephh np->u.event.epname = oldepname; 1120*4436Sstephh return; 1121*4436Sstephh } 1122*4436Sstephh if (epmatches) { 1123*4436Sstephh /* 1124*4436Sstephh * just first part of names match - do wildcarding 1125*4436Sstephh * by using existing wcp including ewname and also 1126*4436Sstephh * copying as much of pwname as is valid, then start 1127*4436Sstephh * vmatch_event() at start of non-matching section 1128*4436Sstephh */ 1129*4436Sstephh for (np1 = oldepname, np2 = np->u.event.epname; 1130*4436Sstephh epmatches != 0; epmatches--) { 1131*4436Sstephh cp = np1->u.name.cp; 1132*4436Sstephh np2->u.name.cp = cp; 1133*4436Sstephh np1 = np1->u.name.next; 1134*4436Sstephh np2 = np2->u.name.next; 1135*4436Sstephh } 1136*4436Sstephh wcp->oldepname = np->u.event.epname; 1137*4436Sstephh wcp->nptop = np; 1138*4436Sstephh vmatch_event(infop, config_child(cp), np2, lnp, 1139*4436Sstephh anp, wcp); 1140*4436Sstephh wcp->oldepname = oldepname; 1141*4436Sstephh wcp->nptop = oldnptop; 1142*4436Sstephh return; 1143*4436Sstephh } 1144*4436Sstephh /* 1145*4436Sstephh * names do not match - allocate a new wcp 1146*4436Sstephh */ 1147*4436Sstephh wcp = MALLOC(sizeof (struct wildcardinfo)); 1148*4436Sstephh wcp->next = wcproot; 1149*4436Sstephh wcproot = wcp; 1150*4436Sstephh wcp->nptop = np; 1151*4436Sstephh wcp->oldepname = np->u.event.epname; 1152*4436Sstephh wcp->ewname = NULL; 1153*4436Sstephh 1154186Sdb35262 vmatch_event(infop, config_child(infop->croot), 1155*4436Sstephh np->u.event.epname, lnp, anp, wcp); 1156*4436Sstephh 1157*4436Sstephh wcproot = wcp->next; 1158*4436Sstephh FREE(wcp); 11590Sstevel@tonic-gate break; 11600Sstevel@tonic-gate } 11610Sstevel@tonic-gate case T_LIST: 11620Sstevel@tonic-gate ASSERT(lnp == NULL); 1163*4436Sstephh vmatch(infop, np->u.expr.right, np->u.expr.left, anp); 11640Sstevel@tonic-gate break; 11650Sstevel@tonic-gate 11660Sstevel@tonic-gate case T_ARROW: 11670Sstevel@tonic-gate ASSERT(lnp == NULL && anp == NULL); 1168*4436Sstephh vmatch(infop, np->u.arrow.rhs, NULL, np->u.arrow.lhs); 11690Sstevel@tonic-gate break; 11700Sstevel@tonic-gate 11710Sstevel@tonic-gate default: 11720Sstevel@tonic-gate outfl(O_DIE, np->file, np->line, 11730Sstevel@tonic-gate "vmatch: unexpected type: %s", 11740Sstevel@tonic-gate ptree_nodetype2str(np->t)); 11750Sstevel@tonic-gate } 11760Sstevel@tonic-gate } 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate static void 11790Sstevel@tonic-gate cp_reset(struct node *np) 11800Sstevel@tonic-gate { 11810Sstevel@tonic-gate if (np == NULL) 11820Sstevel@tonic-gate return; 11830Sstevel@tonic-gate switch (np->t) { 11840Sstevel@tonic-gate case T_NAME: 11850Sstevel@tonic-gate np->u.name.cp = NULL; 11860Sstevel@tonic-gate cp_reset(np->u.name.next); 11870Sstevel@tonic-gate break; 11880Sstevel@tonic-gate 11890Sstevel@tonic-gate case T_LIST: 11900Sstevel@tonic-gate cp_reset(np->u.expr.left); 11910Sstevel@tonic-gate cp_reset(np->u.expr.right); 11920Sstevel@tonic-gate break; 11930Sstevel@tonic-gate 11940Sstevel@tonic-gate case T_ARROW: 11950Sstevel@tonic-gate cp_reset(np->u.arrow.lhs); 11960Sstevel@tonic-gate cp_reset(np->u.arrow.rhs); 11970Sstevel@tonic-gate break; 11980Sstevel@tonic-gate 11990Sstevel@tonic-gate case T_EVENT: 12000Sstevel@tonic-gate cp_reset(np->u.event.epname); 12010Sstevel@tonic-gate break; 12020Sstevel@tonic-gate } 12030Sstevel@tonic-gate } 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate /* 12060Sstevel@tonic-gate * itree_create -- apply the current config to the current parse tree 12070Sstevel@tonic-gate * 12080Sstevel@tonic-gate * returns a lut mapping fully-instance-qualified names to struct events. 12090Sstevel@tonic-gate * 12100Sstevel@tonic-gate */ 12110Sstevel@tonic-gate struct lut * 12120Sstevel@tonic-gate itree_create(struct config *croot) 12130Sstevel@tonic-gate { 12140Sstevel@tonic-gate struct lut *retval; 12150Sstevel@tonic-gate struct node *propnp; 1216*4436Sstephh extern int alloc_total(); 1217*4436Sstephh int init_size; 12180Sstevel@tonic-gate 12190Sstevel@tonic-gate Ninfo.lut = NULL; 12200Sstevel@tonic-gate Ninfo.croot = croot; 1221*4436Sstephh init_size = alloc_total(); 1222*4436Sstephh out(O_ALTFP|O_STAMP, "start itree_create using %d bytes", init_size); 12230Sstevel@tonic-gate for (propnp = Props; propnp; propnp = propnp->u.stmt.next) { 12240Sstevel@tonic-gate struct node *anp = propnp->u.stmt.np; 12250Sstevel@tonic-gate 12260Sstevel@tonic-gate ASSERTeq(anp->t, T_ARROW, ptree_nodetype2str); 12270Sstevel@tonic-gate 1228*4436Sstephh if (!anp->u.arrow.needed) 1229*4436Sstephh continue; 12300Sstevel@tonic-gate Ninfo.anp = anp; 12310Sstevel@tonic-gate Ninfo.ex = NULL; 12320Sstevel@tonic-gate 12330Sstevel@tonic-gate generate_arrownp(anp); 1234*4436Sstephh vmatch(&Ninfo, anp, NULL, NULL); 12350Sstevel@tonic-gate 12360Sstevel@tonic-gate if (Ninfo.ex) { 12370Sstevel@tonic-gate lut_free(Ninfo.ex, iterinfo_destructor, NULL); 12380Sstevel@tonic-gate Ninfo.ex = NULL; 12390Sstevel@tonic-gate } 12400Sstevel@tonic-gate cp_reset(anp); 12410Sstevel@tonic-gate } 12420Sstevel@tonic-gate 1243*4436Sstephh out(O_ALTFP|O_STAMP, "itree_create added %d bytes", 1244*4436Sstephh alloc_total() - init_size); 12450Sstevel@tonic-gate retval = Ninfo.lut; 12460Sstevel@tonic-gate Ninfo.lut = NULL; 12470Sstevel@tonic-gate return (retval); 12480Sstevel@tonic-gate } 12490Sstevel@tonic-gate 1250*4436Sstephh /* 1251*4436Sstephh * initial first pass of the rules. 1252*4436Sstephh * We don't use the config at all. Just check the last part of the pathname 1253*4436Sstephh * in the rules. If this matches the last part of the pathname in the first 1254*4436Sstephh * ereport, then set pathname to the pathname in the ereport. If not then 1255*4436Sstephh * set pathname to just the last part of pathname with instance number 0. 1256*4436Sstephh * Constraints are ignored and all nork values are set to 0. If after all that 1257*4436Sstephh * any rules can still not be associated with the ereport, then they are set 1258*4436Sstephh * to not needed in prune_propagations() and ignored in the real itree_create() 1259*4436Sstephh * which follows. 1260*4436Sstephh */ 1261*4436Sstephh 1262*4436Sstephh static struct event * 1263*4436Sstephh add_event_dummy(struct node *np, const struct ipath *ipp) 1264*4436Sstephh { 1265*4436Sstephh struct event *ret; 1266*4436Sstephh struct event searchevent; /* just used for searching */ 1267*4436Sstephh extern struct ipath *ipath_dummy(struct node *, struct ipath *); 1268*4436Sstephh 1269*4436Sstephh searchevent.enode = np; 1270*4436Sstephh searchevent.ipp = ipath_dummy(np->u.event.epname, (struct ipath *)ipp); 1271*4436Sstephh if ((ret = lut_lookup(Ninfo.lut, (void *)&searchevent, 1272*4436Sstephh (lut_cmp)event_cmp)) != NULL) 1273*4436Sstephh return (ret); 1274*4436Sstephh 1275*4436Sstephh ret = alloc_xmalloc(sizeof (*ret)); 1276*4436Sstephh bzero(ret, sizeof (*ret)); 1277*4436Sstephh ret->t = np->u.event.ename->u.name.t; 1278*4436Sstephh ret->enode = np; 1279*4436Sstephh ret->ipp = searchevent.ipp; 1280*4436Sstephh Ninfo.lut = lut_add(Ninfo.lut, (void *)ret, (void *)ret, 1281*4436Sstephh (lut_cmp)event_cmp); 1282*4436Sstephh return (ret); 1283*4436Sstephh } 1284*4436Sstephh 1285*4436Sstephh /*ARGSUSED*/ 1286*4436Sstephh struct lut * 1287*4436Sstephh itree_create_dummy(const char *e0class, const struct ipath *e0ipp) 1288*4436Sstephh { 1289*4436Sstephh struct node *propnp; 1290*4436Sstephh struct event *frome, *toe; 1291*4436Sstephh struct bubble *frombp, *tobp; 1292*4436Sstephh struct arrow *arrowp; 1293*4436Sstephh struct node *src, *dst, *slst, *dlst, *arrownp, *oldarrownp; 1294*4436Sstephh int gen = 0; 1295*4436Sstephh extern int alloc_total(); 1296*4436Sstephh int init_size; 1297*4436Sstephh 1298*4436Sstephh Ninfo.lut = NULL; 1299*4436Sstephh init_size = alloc_total(); 1300*4436Sstephh out(O_ALTFP|O_STAMP, "start itree_create using %d bytes", init_size); 1301*4436Sstephh for (propnp = Props; propnp; propnp = propnp->u.stmt.next) { 1302*4436Sstephh arrownp = propnp->u.stmt.np; 1303*4436Sstephh while (arrownp) { 1304*4436Sstephh gen++; 1305*4436Sstephh dlst = arrownp->u.arrow.rhs; 1306*4436Sstephh slst = arrownp->u.arrow.lhs; 1307*4436Sstephh oldarrownp = arrownp; 1308*4436Sstephh if (slst->t == T_ARROW) { 1309*4436Sstephh arrownp = slst; 1310*4436Sstephh slst = slst->u.arrow.rhs; 1311*4436Sstephh } else { 1312*4436Sstephh arrownp = NULL; 1313*4436Sstephh } 1314*4436Sstephh while (slst) { 1315*4436Sstephh if (slst->t == T_LIST) { 1316*4436Sstephh src = slst->u.expr.right; 1317*4436Sstephh slst = slst->u.expr.left; 1318*4436Sstephh } else { 1319*4436Sstephh src = slst; 1320*4436Sstephh slst = NULL; 1321*4436Sstephh } 1322*4436Sstephh frome = add_event_dummy(src, e0ipp); 1323*4436Sstephh frombp = itree_add_bubble(frome, B_FROM, 0, 0); 1324*4436Sstephh while (dlst) { 1325*4436Sstephh if (dlst->t == T_LIST) { 1326*4436Sstephh dst = dlst->u.expr.right; 1327*4436Sstephh dlst = dlst->u.expr.left; 1328*4436Sstephh } else { 1329*4436Sstephh dst = dlst; 1330*4436Sstephh dlst = NULL; 1331*4436Sstephh } 1332*4436Sstephh arrowp = alloc_xmalloc( 1333*4436Sstephh sizeof (struct arrow)); 1334*4436Sstephh bzero(arrowp, sizeof (struct arrow)); 1335*4436Sstephh arrowp->pnode = oldarrownp; 1336*4436Sstephh toe = add_event_dummy(dst, e0ipp); 1337*4436Sstephh tobp = itree_add_bubble(toe, B_TO, 0, 1338*4436Sstephh gen); 1339*4436Sstephh arrowp->tail = frombp; 1340*4436Sstephh arrowp->head = tobp; 1341*4436Sstephh add_arrow(frombp, arrowp); 1342*4436Sstephh add_arrow(tobp, arrowp); 1343*4436Sstephh arrow_add_within(arrowp, 1344*4436Sstephh dst->u.event.declp->u.stmt.np-> 1345*4436Sstephh u.event.eexprlist); 1346*4436Sstephh arrow_add_within(arrowp, 1347*4436Sstephh dst->u.event.eexprlist); 1348*4436Sstephh } 1349*4436Sstephh } 1350*4436Sstephh } 1351*4436Sstephh } 1352*4436Sstephh out(O_ALTFP|O_STAMP, "itree_create added %d bytes", 1353*4436Sstephh alloc_total() - init_size); 1354*4436Sstephh return (Ninfo.lut); 1355*4436Sstephh } 1356*4436Sstephh 13570Sstevel@tonic-gate void 13580Sstevel@tonic-gate itree_free(struct lut *lutp) 13590Sstevel@tonic-gate { 1360*4436Sstephh int init_size; 1361*4436Sstephh 1362*4436Sstephh init_size = alloc_total(); 1363*4436Sstephh out(O_ALTFP|O_STAMP, "start itree_free"); 13640Sstevel@tonic-gate lut_free(lutp, itree_destructor, NULL); 1365*4436Sstephh out(O_ALTFP|O_STAMP, "itree_free freed %d bytes", 1366*4436Sstephh init_size - alloc_total()); 13670Sstevel@tonic-gate } 13680Sstevel@tonic-gate 13691865Sdilpreet void 13701865Sdilpreet itree_prune(struct lut *lutp) 13711865Sdilpreet { 1372*4436Sstephh int init_size; 13730Sstevel@tonic-gate 1374*4436Sstephh init_size = alloc_total(); 1375*4436Sstephh out(O_ALTFP|O_STAMP, "start itree_prune"); 1376*4436Sstephh lut_walk(lutp, itree_pruner, NULL); 1377*4436Sstephh out(O_ALTFP|O_STAMP, "itree_prune freed %d bytes", 1378*4436Sstephh init_size - alloc_total()); 13790Sstevel@tonic-gate } 13800Sstevel@tonic-gate 13810Sstevel@tonic-gate void 13820Sstevel@tonic-gate itree_pevent_brief(int flags, struct event *ep) 13830Sstevel@tonic-gate { 13840Sstevel@tonic-gate ASSERT(ep != NULL); 13850Sstevel@tonic-gate ASSERT(ep->enode != NULL); 13860Sstevel@tonic-gate ASSERT(ep->ipp != NULL); 13870Sstevel@tonic-gate 13880Sstevel@tonic-gate ipath_print(flags, ep->enode->u.event.ename->u.name.s, ep->ipp); 13890Sstevel@tonic-gate } 13900Sstevel@tonic-gate 13910Sstevel@tonic-gate /*ARGSUSED*/ 13920Sstevel@tonic-gate static void 13930Sstevel@tonic-gate itree_pevent(struct event *lhs, struct event *ep, void *arg) 13940Sstevel@tonic-gate { 13950Sstevel@tonic-gate struct plut_wlk_data propd; 13960Sstevel@tonic-gate struct bubble *bp; 13970Sstevel@tonic-gate int flags = (int)arg; 13980Sstevel@tonic-gate 13990Sstevel@tonic-gate itree_pevent_brief(flags, ep); 14000Sstevel@tonic-gate if (ep->t == N_EREPORT) 14010Sstevel@tonic-gate out(flags, " (count %d)", ep->count); 14020Sstevel@tonic-gate else 14030Sstevel@tonic-gate out(flags, NULL); 14040Sstevel@tonic-gate 14050Sstevel@tonic-gate if (ep->props) { 14060Sstevel@tonic-gate propd.flags = flags; 14070Sstevel@tonic-gate propd.first = 1; 14080Sstevel@tonic-gate out(flags, "Properties:"); 14090Sstevel@tonic-gate lut_walk(ep->props, ptree_plut, (void *)&propd); 14100Sstevel@tonic-gate } 14110Sstevel@tonic-gate 14120Sstevel@tonic-gate for (bp = itree_next_bubble(ep, NULL); bp; 14130Sstevel@tonic-gate bp = itree_next_bubble(ep, bp)) { 14140Sstevel@tonic-gate /* Print only TO bubbles in this loop */ 14150Sstevel@tonic-gate if (bp->t != B_TO) 14160Sstevel@tonic-gate continue; 14170Sstevel@tonic-gate itree_pbubble(flags, bp); 14180Sstevel@tonic-gate } 14190Sstevel@tonic-gate 14200Sstevel@tonic-gate for (bp = itree_next_bubble(ep, NULL); bp; 14210Sstevel@tonic-gate bp = itree_next_bubble(ep, bp)) { 14220Sstevel@tonic-gate /* Print only INHIBIT bubbles in this loop */ 14230Sstevel@tonic-gate if (bp->t != B_INHIBIT) 14240Sstevel@tonic-gate continue; 14250Sstevel@tonic-gate itree_pbubble(flags, bp); 14260Sstevel@tonic-gate } 14270Sstevel@tonic-gate 14280Sstevel@tonic-gate for (bp = itree_next_bubble(ep, NULL); bp; 14290Sstevel@tonic-gate bp = itree_next_bubble(ep, bp)) { 14300Sstevel@tonic-gate /* Print only FROM bubbles in this loop */ 14310Sstevel@tonic-gate if (bp->t != B_FROM) 14320Sstevel@tonic-gate continue; 14330Sstevel@tonic-gate itree_pbubble(flags, bp); 14340Sstevel@tonic-gate } 14350Sstevel@tonic-gate } 14360Sstevel@tonic-gate 14370Sstevel@tonic-gate static void 14380Sstevel@tonic-gate itree_pbubble(int flags, struct bubble *bp) 14390Sstevel@tonic-gate { 14400Sstevel@tonic-gate struct constraintlist *cp; 14410Sstevel@tonic-gate struct arrowlist *ap; 14420Sstevel@tonic-gate 14430Sstevel@tonic-gate ASSERT(bp != NULL); 14440Sstevel@tonic-gate 14450Sstevel@tonic-gate out(flags|O_NONL, " "); 14460Sstevel@tonic-gate if (bp->mark) 14470Sstevel@tonic-gate out(flags|O_NONL, "*"); 14480Sstevel@tonic-gate else 14490Sstevel@tonic-gate out(flags|O_NONL, " "); 14500Sstevel@tonic-gate if (bp->t == B_FROM) 14510Sstevel@tonic-gate out(flags|O_NONL, "N=%d to:", bp->nork); 14520Sstevel@tonic-gate else if (bp->t == B_TO) 14530Sstevel@tonic-gate out(flags|O_NONL, "K=%d from:", bp->nork); 14540Sstevel@tonic-gate else 14550Sstevel@tonic-gate out(flags|O_NONL, "K=%d masked from:", bp->nork); 14560Sstevel@tonic-gate 14570Sstevel@tonic-gate if (bp->t == B_TO || bp->t == B_INHIBIT) { 14580Sstevel@tonic-gate for (ap = itree_next_arrow(bp, NULL); ap; 14590Sstevel@tonic-gate ap = itree_next_arrow(bp, ap)) { 14600Sstevel@tonic-gate ASSERT(ap->arrowp->head == bp); 14610Sstevel@tonic-gate ASSERT(ap->arrowp->tail != NULL); 14620Sstevel@tonic-gate ASSERT(ap->arrowp->tail->myevent != NULL); 14630Sstevel@tonic-gate out(flags|O_NONL, " "); 14640Sstevel@tonic-gate itree_pevent_brief(flags, ap->arrowp->tail->myevent); 14650Sstevel@tonic-gate } 14660Sstevel@tonic-gate out(flags, NULL); 14670Sstevel@tonic-gate return; 14680Sstevel@tonic-gate } 14690Sstevel@tonic-gate 14700Sstevel@tonic-gate for (ap = itree_next_arrow(bp, NULL); ap; 14710Sstevel@tonic-gate ap = itree_next_arrow(bp, ap)) { 14720Sstevel@tonic-gate ASSERT(ap->arrowp->tail == bp); 14730Sstevel@tonic-gate ASSERT(ap->arrowp->head != NULL); 14740Sstevel@tonic-gate ASSERT(ap->arrowp->head->myevent != NULL); 14750Sstevel@tonic-gate 14760Sstevel@tonic-gate out(flags|O_NONL, " "); 14770Sstevel@tonic-gate itree_pevent_brief(flags, ap->arrowp->head->myevent); 14780Sstevel@tonic-gate 14790Sstevel@tonic-gate out(flags|O_NONL, " "); 14800Sstevel@tonic-gate ptree_timeval(flags, &ap->arrowp->mindelay); 14810Sstevel@tonic-gate out(flags|O_NONL, ","); 14820Sstevel@tonic-gate ptree_timeval(flags, &ap->arrowp->maxdelay); 14830Sstevel@tonic-gate 14840Sstevel@tonic-gate /* Display anything from the propogation node? */ 14850Sstevel@tonic-gate out(O_VERB3|O_NONL, " <%s:%d>", 14860Sstevel@tonic-gate ap->arrowp->pnode->file, ap->arrowp->pnode->line); 14870Sstevel@tonic-gate 14880Sstevel@tonic-gate if (itree_next_constraint(ap->arrowp, NULL)) 14890Sstevel@tonic-gate out(flags|O_NONL, " {"); 14900Sstevel@tonic-gate 14910Sstevel@tonic-gate for (cp = itree_next_constraint(ap->arrowp, NULL); cp; 14920Sstevel@tonic-gate cp = itree_next_constraint(ap->arrowp, cp)) { 14930Sstevel@tonic-gate ptree(flags, cp->cnode, 1, 0); 14940Sstevel@tonic-gate if (itree_next_constraint(ap->arrowp, cp)) 14950Sstevel@tonic-gate out(flags|O_NONL, ", "); 14960Sstevel@tonic-gate } 14970Sstevel@tonic-gate 14980Sstevel@tonic-gate if (itree_next_constraint(ap->arrowp, NULL)) 14990Sstevel@tonic-gate out(flags|O_NONL, "}"); 15000Sstevel@tonic-gate } 15010Sstevel@tonic-gate out(flags, NULL); 15020Sstevel@tonic-gate } 15030Sstevel@tonic-gate 15040Sstevel@tonic-gate void 15050Sstevel@tonic-gate itree_ptree(int flags, struct lut *itp) 15060Sstevel@tonic-gate { 15070Sstevel@tonic-gate lut_walk(itp, (lut_cb)itree_pevent, (void *)flags); 15080Sstevel@tonic-gate } 15090Sstevel@tonic-gate 15100Sstevel@tonic-gate /*ARGSUSED*/ 15110Sstevel@tonic-gate static void 15120Sstevel@tonic-gate itree_destructor(void *left, void *right, void *arg) 15130Sstevel@tonic-gate { 15140Sstevel@tonic-gate struct event *ep = (struct event *)right; 15150Sstevel@tonic-gate struct bubble *nextbub, *bub; 15160Sstevel@tonic-gate 15170Sstevel@tonic-gate /* Free the properties */ 15181865Sdilpreet if (ep->props) 15191865Sdilpreet lut_free(ep->props, instances_destructor, NULL); 15200Sstevel@tonic-gate 15211414Scindi /* Free the payload properties */ 15221865Sdilpreet if (ep->payloadprops) 15231865Sdilpreet lut_free(ep->payloadprops, payloadprops_destructor, NULL); 15241414Scindi 15250Sstevel@tonic-gate /* Free my bubbles */ 15260Sstevel@tonic-gate for (bub = ep->bubbles; bub != NULL; ) { 15270Sstevel@tonic-gate nextbub = bub->next; 15280Sstevel@tonic-gate /* 15290Sstevel@tonic-gate * Free arrows if they are FROM me. Free arrowlists on 15300Sstevel@tonic-gate * other types of bubbles (but not the attached arrows, 15310Sstevel@tonic-gate * which will be freed when we free the originating 15320Sstevel@tonic-gate * bubble. 15330Sstevel@tonic-gate */ 15340Sstevel@tonic-gate if (bub->t == B_FROM) 15350Sstevel@tonic-gate itree_free_arrowlists(bub, 1); 15360Sstevel@tonic-gate else 15370Sstevel@tonic-gate itree_free_arrowlists(bub, 0); 15380Sstevel@tonic-gate itree_free_bubble(bub); 15390Sstevel@tonic-gate bub = nextbub; 15400Sstevel@tonic-gate } 15410Sstevel@tonic-gate 15420Sstevel@tonic-gate if (ep->nvp != NULL) 15430Sstevel@tonic-gate nvlist_free(ep->nvp); 1544*4436Sstephh alloc_xfree(ep, sizeof (*ep)); 15450Sstevel@tonic-gate } 15460Sstevel@tonic-gate 15471865Sdilpreet /*ARGSUSED*/ 15481865Sdilpreet static void 15491865Sdilpreet itree_pruner(void *left, void *right, void *arg) 15501865Sdilpreet { 15511865Sdilpreet struct event *ep = (struct event *)right; 15521865Sdilpreet struct bubble *nextbub, *bub; 15531865Sdilpreet 15541865Sdilpreet if (ep->keep_in_tree) 15551865Sdilpreet return; 15561865Sdilpreet 15571865Sdilpreet /* Free the properties */ 15581865Sdilpreet lut_free(ep->props, instances_destructor, NULL); 15591865Sdilpreet 15601865Sdilpreet /* Free the payload properties */ 15611865Sdilpreet lut_free(ep->payloadprops, payloadprops_destructor, NULL); 15621865Sdilpreet 15631865Sdilpreet /* Free my bubbles */ 15641865Sdilpreet for (bub = ep->bubbles; bub != NULL; ) { 15651865Sdilpreet nextbub = bub->next; 15661865Sdilpreet itree_prune_arrowlists(bub); 15671865Sdilpreet itree_free_bubble(bub); 15681865Sdilpreet bub = nextbub; 15691865Sdilpreet } 15701865Sdilpreet 15711865Sdilpreet if (ep->nvp != NULL) 15721865Sdilpreet nvlist_free(ep->nvp); 15731865Sdilpreet ep->props = NULL; 15741865Sdilpreet ep->payloadprops = NULL; 15751865Sdilpreet ep->bubbles = NULL; 15761865Sdilpreet ep->nvp = NULL; 15771865Sdilpreet } 15781865Sdilpreet 15790Sstevel@tonic-gate static void 15800Sstevel@tonic-gate itree_free_bubble(struct bubble *freeme) 15810Sstevel@tonic-gate { 1582*4436Sstephh alloc_xfree(freeme, sizeof (*freeme)); 15830Sstevel@tonic-gate } 15840Sstevel@tonic-gate 15850Sstevel@tonic-gate static struct bubble * 15860Sstevel@tonic-gate itree_add_bubble(struct event *eventp, enum bubbletype btype, int nork, int gen) 15870Sstevel@tonic-gate { 15880Sstevel@tonic-gate struct bubble *prev = NULL; 15890Sstevel@tonic-gate struct bubble *curr; 15900Sstevel@tonic-gate struct bubble *newb; 15910Sstevel@tonic-gate 15920Sstevel@tonic-gate /* Use existing bubbles as appropriate when possible */ 15930Sstevel@tonic-gate for (curr = eventp->bubbles; 15940Sstevel@tonic-gate curr != NULL; 15950Sstevel@tonic-gate prev = curr, curr = curr->next) { 15960Sstevel@tonic-gate if (btype == B_TO && curr->t == B_TO) { 15970Sstevel@tonic-gate /* see if an existing "to" bubble works for us */ 15980Sstevel@tonic-gate if (gen == curr->gen) 15990Sstevel@tonic-gate return (curr); /* matched gen number */ 16000Sstevel@tonic-gate else if (nork == 1 && curr->nork == 1) { 16010Sstevel@tonic-gate curr->gen = gen; 16020Sstevel@tonic-gate return (curr); /* coalesce K==1 bubbles */ 16030Sstevel@tonic-gate } 16040Sstevel@tonic-gate } else if (btype == B_FROM && curr->t == B_FROM) { 16050Sstevel@tonic-gate /* see if an existing "from" bubble works for us */ 16060Sstevel@tonic-gate if ((nork == N_IS_ALL && curr->nork == N_IS_ALL) || 16070Sstevel@tonic-gate (nork == 0 && curr->nork == 0)) 16080Sstevel@tonic-gate return (curr); 16090Sstevel@tonic-gate } 16100Sstevel@tonic-gate } 16110Sstevel@tonic-gate 1612*4436Sstephh newb = alloc_xmalloc(sizeof (struct bubble)); 16130Sstevel@tonic-gate newb->next = NULL; 16140Sstevel@tonic-gate newb->t = btype; 16150Sstevel@tonic-gate newb->myevent = eventp; 16160Sstevel@tonic-gate newb->nork = nork; 16170Sstevel@tonic-gate newb->mark = 0; 16180Sstevel@tonic-gate newb->gen = gen; 16190Sstevel@tonic-gate newb->arrows = NULL; 16200Sstevel@tonic-gate 16210Sstevel@tonic-gate if (prev == NULL) 16220Sstevel@tonic-gate eventp->bubbles = newb; 16230Sstevel@tonic-gate else 16240Sstevel@tonic-gate prev->next = newb; 16250Sstevel@tonic-gate 16260Sstevel@tonic-gate return (newb); 16270Sstevel@tonic-gate } 16280Sstevel@tonic-gate 16290Sstevel@tonic-gate struct bubble * 16300Sstevel@tonic-gate itree_next_bubble(struct event *eventp, struct bubble *last) 16310Sstevel@tonic-gate { 16320Sstevel@tonic-gate struct bubble *next; 16330Sstevel@tonic-gate 16340Sstevel@tonic-gate for (;;) { 16350Sstevel@tonic-gate if (last != NULL) 16360Sstevel@tonic-gate next = last->next; 16370Sstevel@tonic-gate else 16380Sstevel@tonic-gate next = eventp->bubbles; 16390Sstevel@tonic-gate 16400Sstevel@tonic-gate if (next == NULL || next->arrows != NULL) 16410Sstevel@tonic-gate return (next); 16420Sstevel@tonic-gate 16430Sstevel@tonic-gate /* bubble was empty, skip it */ 16440Sstevel@tonic-gate last = next; 16450Sstevel@tonic-gate } 16460Sstevel@tonic-gate } 16470Sstevel@tonic-gate 16480Sstevel@tonic-gate static void 16490Sstevel@tonic-gate add_arrow(struct bubble *bp, struct arrow *ap) 16500Sstevel@tonic-gate { 16510Sstevel@tonic-gate struct arrowlist *prev = NULL; 16520Sstevel@tonic-gate struct arrowlist *curr; 16530Sstevel@tonic-gate struct arrowlist *newal; 16540Sstevel@tonic-gate 1655*4436Sstephh newal = alloc_xmalloc(sizeof (struct arrowlist)); 16560Sstevel@tonic-gate bzero(newal, sizeof (struct arrowlist)); 16570Sstevel@tonic-gate newal->arrowp = ap; 16580Sstevel@tonic-gate 16590Sstevel@tonic-gate curr = itree_next_arrow(bp, NULL); 16600Sstevel@tonic-gate while (curr != NULL) { 16610Sstevel@tonic-gate prev = curr; 16620Sstevel@tonic-gate curr = itree_next_arrow(bp, curr); 16630Sstevel@tonic-gate } 16640Sstevel@tonic-gate 16650Sstevel@tonic-gate if (prev == NULL) 16660Sstevel@tonic-gate bp->arrows = newal; 16670Sstevel@tonic-gate else 16680Sstevel@tonic-gate prev->next = newal; 16690Sstevel@tonic-gate } 16700Sstevel@tonic-gate 16710Sstevel@tonic-gate static struct arrow * 1672*4436Sstephh itree_add_arrow(struct node *apnode, struct node *fromevent, 1673*4436Sstephh struct node *toevent, struct lut *ex) 16740Sstevel@tonic-gate { 16750Sstevel@tonic-gate struct arrow *newa; 16760Sstevel@tonic-gate 1677*4436Sstephh newa = alloc_xmalloc(sizeof (struct arrow)); 16781414Scindi bzero(newa, sizeof (struct arrow)); 16790Sstevel@tonic-gate newa->pnode = apnode; 16800Sstevel@tonic-gate newa->constraints = NULL; 16810Sstevel@tonic-gate 16820Sstevel@tonic-gate /* 16830Sstevel@tonic-gate * Set default delays, then try to re-set them from 16840Sstevel@tonic-gate * any within() constraints. 16850Sstevel@tonic-gate */ 16860Sstevel@tonic-gate newa->mindelay = newa->maxdelay = 0ULL; 16870Sstevel@tonic-gate if (itree_set_arrow_traits(newa, fromevent, toevent, ex) == 0) { 1688*4436Sstephh alloc_xfree(newa, sizeof (struct arrow)); 16890Sstevel@tonic-gate return (NULL); 16900Sstevel@tonic-gate } 16910Sstevel@tonic-gate 16920Sstevel@tonic-gate return (newa); 16930Sstevel@tonic-gate } 16940Sstevel@tonic-gate 16950Sstevel@tonic-gate /* returns false if traits show that arrow should not be added after all */ 16960Sstevel@tonic-gate static int 16970Sstevel@tonic-gate itree_set_arrow_traits(struct arrow *ap, struct node *fromev, 16980Sstevel@tonic-gate struct node *toev, struct lut *ex) 16990Sstevel@tonic-gate { 1700*4436Sstephh struct node *events[] = { NULL, NULL, NULL }; 17010Sstevel@tonic-gate struct node *newc = NULL; 17020Sstevel@tonic-gate 17030Sstevel@tonic-gate ASSERTeq(fromev->t, T_EVENT, ptree_nodetype2str); 17040Sstevel@tonic-gate ASSERTeq(toev->t, T_EVENT, ptree_nodetype2str); 17050Sstevel@tonic-gate 17060Sstevel@tonic-gate /* 17070Sstevel@tonic-gate * search for the within values first on the declaration of 17080Sstevel@tonic-gate * the destination event, and then on the prop. this allows 17090Sstevel@tonic-gate * one to specify a "default" within by putting it on the 17100Sstevel@tonic-gate * declaration, but then allow overriding on the prop statement. 17110Sstevel@tonic-gate */ 17120Sstevel@tonic-gate arrow_add_within(ap, toev->u.event.declp->u.stmt.np->u.event.eexprlist); 17130Sstevel@tonic-gate arrow_add_within(ap, toev->u.event.eexprlist); 17140Sstevel@tonic-gate 17150Sstevel@tonic-gate /* 17160Sstevel@tonic-gate * handle any global constraints inherited from the 17170Sstevel@tonic-gate * "fromev" event's declaration 17180Sstevel@tonic-gate */ 17190Sstevel@tonic-gate ASSERT(fromev->u.event.declp != NULL); 17200Sstevel@tonic-gate ASSERT(fromev->u.event.declp->u.stmt.np != NULL); 17210Sstevel@tonic-gate 17220Sstevel@tonic-gate #ifdef notdef 17230Sstevel@tonic-gate /* XXX not quite ready to evaluate constraints from decls yet */ 17240Sstevel@tonic-gate if (fromev->u.event.declp->u.stmt.np->u.event.eexprlist) 17250Sstevel@tonic-gate (void) itree_add_constraint(ap, 17260Sstevel@tonic-gate fromev->u.event.declp->u.stmt.np->u.event.eexprlist); 17270Sstevel@tonic-gate #endif /* notdef */ 17280Sstevel@tonic-gate 17290Sstevel@tonic-gate /* handle constraints on the from event in the prop statement */ 1730*4436Sstephh events[0] = fromev; 1731*4436Sstephh events[1] = toev; 1732*4436Sstephh if (eval_potential(fromev->u.event.eexprlist, ex, events, &newc, 17332318Sstephh Ninfo.croot) == 0) 17340Sstevel@tonic-gate return (0); /* constraint disallows arrow */ 17350Sstevel@tonic-gate 17360Sstevel@tonic-gate /* 17370Sstevel@tonic-gate * handle any global constraints inherited from the 17380Sstevel@tonic-gate * "toev" event's declaration 17390Sstevel@tonic-gate */ 17400Sstevel@tonic-gate ASSERT(toev->u.event.declp != NULL); 17410Sstevel@tonic-gate ASSERT(toev->u.event.declp->u.stmt.np != NULL); 17420Sstevel@tonic-gate 17430Sstevel@tonic-gate #ifdef notdef 17440Sstevel@tonic-gate /* XXX not quite ready to evaluate constraints from decls yet */ 17450Sstevel@tonic-gate if (toev->u.event.declp->u.stmt.np->u.event.eexprlist) 17460Sstevel@tonic-gate (void) itree_add_constraint(ap, 17470Sstevel@tonic-gate toev->u.event.declp->u.stmt.np->u.event.eexprlist); 17480Sstevel@tonic-gate #endif /* notdef */ 17490Sstevel@tonic-gate 17500Sstevel@tonic-gate /* handle constraints on the to event in the prop statement */ 1751*4436Sstephh events[0] = toev; 1752*4436Sstephh events[1] = fromev; 1753*4436Sstephh if (eval_potential(toev->u.event.eexprlist, ex, events, &newc, 17542318Sstephh Ninfo.croot) == 0) { 17551865Sdilpreet if (newc != NULL) 17561865Sdilpreet tree_free(newc); 17570Sstevel@tonic-gate return (0); /* constraint disallows arrow */ 17581865Sdilpreet } 17590Sstevel@tonic-gate 17600Sstevel@tonic-gate /* if we came up with any deferred constraints, add them to arrow */ 1761*4436Sstephh if (newc != NULL) { 1762*4436Sstephh out(O_ALTFP|O_VERB3, "(deferred constraints)"); 17631414Scindi (void) itree_add_constraint(ap, iexpr(newc)); 1764*4436Sstephh } 17650Sstevel@tonic-gate 17660Sstevel@tonic-gate return (1); /* constraints allow arrow */ 17670Sstevel@tonic-gate } 17680Sstevel@tonic-gate 17690Sstevel@tonic-gate /* 17700Sstevel@tonic-gate * Set within() constraint. If the constraint were set multiple times, 17710Sstevel@tonic-gate * the last one would "win". 17720Sstevel@tonic-gate */ 17730Sstevel@tonic-gate static void 17740Sstevel@tonic-gate arrow_add_within(struct arrow *ap, struct node *xpr) 17750Sstevel@tonic-gate { 17760Sstevel@tonic-gate struct node *arglist; 17770Sstevel@tonic-gate 17780Sstevel@tonic-gate /* end of expressions list */ 17790Sstevel@tonic-gate if (xpr == NULL) 17800Sstevel@tonic-gate return; 17810Sstevel@tonic-gate 17820Sstevel@tonic-gate switch (xpr->t) { 17830Sstevel@tonic-gate case T_LIST: 17840Sstevel@tonic-gate arrow_add_within(ap, xpr->u.expr.left); 17850Sstevel@tonic-gate arrow_add_within(ap, xpr->u.expr.right); 17860Sstevel@tonic-gate return; 17870Sstevel@tonic-gate case T_FUNC: 17880Sstevel@tonic-gate if (xpr->u.func.s != L_within) 17890Sstevel@tonic-gate return; 17900Sstevel@tonic-gate arglist = xpr->u.func.arglist; 17910Sstevel@tonic-gate switch (arglist->t) { 17920Sstevel@tonic-gate case T_TIMEVAL: 17930Sstevel@tonic-gate ap->mindelay = 0; 17940Sstevel@tonic-gate ap->maxdelay = arglist->u.ull; 17950Sstevel@tonic-gate break; 17960Sstevel@tonic-gate case T_NAME: 17970Sstevel@tonic-gate ASSERT(arglist->u.name.s == L_infinity); 17980Sstevel@tonic-gate ap->mindelay = 0; 17990Sstevel@tonic-gate ap->maxdelay = TIMEVAL_EVENTUALLY; 18000Sstevel@tonic-gate break; 18010Sstevel@tonic-gate case T_LIST: 18020Sstevel@tonic-gate ASSERT(arglist->u.expr.left->t == T_TIMEVAL); 18030Sstevel@tonic-gate ap->mindelay = arglist->u.expr.left->u.ull; 18040Sstevel@tonic-gate switch (arglist->u.expr.right->t) { 18050Sstevel@tonic-gate case T_TIMEVAL: 18060Sstevel@tonic-gate ap->maxdelay = arglist->u.ull; 18070Sstevel@tonic-gate break; 18080Sstevel@tonic-gate case T_NAME: 18090Sstevel@tonic-gate ASSERT(arglist->u.expr.right->u.name.s == 18100Sstevel@tonic-gate L_infinity); 18110Sstevel@tonic-gate ap->maxdelay = TIMEVAL_EVENTUALLY; 18120Sstevel@tonic-gate break; 18130Sstevel@tonic-gate default: 18140Sstevel@tonic-gate out(O_DIE, "within: unexpected 2nd arg type"); 18150Sstevel@tonic-gate } 18160Sstevel@tonic-gate break; 18170Sstevel@tonic-gate default: 18180Sstevel@tonic-gate out(O_DIE, "within: unexpected 1st arg type"); 18190Sstevel@tonic-gate } 18200Sstevel@tonic-gate break; 18210Sstevel@tonic-gate default: 18220Sstevel@tonic-gate return; 18230Sstevel@tonic-gate } 18240Sstevel@tonic-gate } 18250Sstevel@tonic-gate 18260Sstevel@tonic-gate static void 18270Sstevel@tonic-gate itree_free_arrowlists(struct bubble *bubp, int arrows_too) 18280Sstevel@tonic-gate { 18290Sstevel@tonic-gate struct arrowlist *al, *nal; 18300Sstevel@tonic-gate 18310Sstevel@tonic-gate al = bubp->arrows; 18320Sstevel@tonic-gate while (al != NULL) { 18330Sstevel@tonic-gate nal = al->next; 18340Sstevel@tonic-gate if (arrows_too) { 18350Sstevel@tonic-gate itree_free_constraints(al->arrowp); 1836*4436Sstephh alloc_xfree(al->arrowp, sizeof (struct arrow)); 18370Sstevel@tonic-gate } 1838*4436Sstephh alloc_xfree(al, sizeof (*al)); 18390Sstevel@tonic-gate al = nal; 18400Sstevel@tonic-gate } 18410Sstevel@tonic-gate } 18420Sstevel@tonic-gate 18431865Sdilpreet static void 18441865Sdilpreet itree_delete_arrow(struct bubble *bubp, struct arrow *arrow) 18451865Sdilpreet { 18461865Sdilpreet struct arrowlist *al, *oal; 18471865Sdilpreet 18481865Sdilpreet al = bubp->arrows; 18491865Sdilpreet if (al->arrowp == arrow) { 18501865Sdilpreet bubp->arrows = al->next; 1851*4436Sstephh alloc_xfree(al, sizeof (*al)); 18521865Sdilpreet return; 18531865Sdilpreet } 18541865Sdilpreet while (al != NULL) { 18551865Sdilpreet oal = al; 18561865Sdilpreet al = al->next; 18571865Sdilpreet ASSERT(al != NULL); 18581865Sdilpreet if (al->arrowp == arrow) { 18591865Sdilpreet oal->next = al->next; 1860*4436Sstephh alloc_xfree(al, sizeof (*al)); 18611865Sdilpreet return; 18621865Sdilpreet } 18631865Sdilpreet } 18641865Sdilpreet } 18651865Sdilpreet 18661865Sdilpreet static void 18671865Sdilpreet itree_prune_arrowlists(struct bubble *bubp) 18681865Sdilpreet { 18691865Sdilpreet struct arrowlist *al, *nal; 18701865Sdilpreet 18711865Sdilpreet al = bubp->arrows; 18721865Sdilpreet while (al != NULL) { 18731865Sdilpreet nal = al->next; 18741865Sdilpreet if (bubp->t == B_FROM) 18751865Sdilpreet itree_delete_arrow(al->arrowp->head, al->arrowp); 18761865Sdilpreet else 18771865Sdilpreet itree_delete_arrow(al->arrowp->tail, al->arrowp); 18781865Sdilpreet itree_free_constraints(al->arrowp); 1879*4436Sstephh alloc_xfree(al->arrowp, sizeof (struct arrow)); 1880*4436Sstephh alloc_xfree(al, sizeof (*al)); 18811865Sdilpreet al = nal; 18821865Sdilpreet } 18831865Sdilpreet } 18841865Sdilpreet 18850Sstevel@tonic-gate struct arrowlist * 18860Sstevel@tonic-gate itree_next_arrow(struct bubble *bubble, struct arrowlist *last) 18870Sstevel@tonic-gate { 18880Sstevel@tonic-gate struct arrowlist *next; 18890Sstevel@tonic-gate 18900Sstevel@tonic-gate if (last != NULL) 18910Sstevel@tonic-gate next = last->next; 18920Sstevel@tonic-gate else 18930Sstevel@tonic-gate next = bubble->arrows; 18940Sstevel@tonic-gate return (next); 18950Sstevel@tonic-gate } 18960Sstevel@tonic-gate 18970Sstevel@tonic-gate static struct constraintlist * 18980Sstevel@tonic-gate itree_add_constraint(struct arrow *arrowp, struct node *c) 18990Sstevel@tonic-gate { 19000Sstevel@tonic-gate struct constraintlist *prev = NULL; 19010Sstevel@tonic-gate struct constraintlist *curr; 19020Sstevel@tonic-gate struct constraintlist *newc; 19030Sstevel@tonic-gate 19040Sstevel@tonic-gate for (curr = arrowp->constraints; 19050Sstevel@tonic-gate curr != NULL; 1906*4436Sstephh prev = curr, curr = curr->next) 1907*4436Sstephh ; 19080Sstevel@tonic-gate 1909*4436Sstephh newc = alloc_xmalloc(sizeof (struct constraintlist)); 19100Sstevel@tonic-gate newc->next = NULL; 19110Sstevel@tonic-gate newc->cnode = c; 19120Sstevel@tonic-gate 19130Sstevel@tonic-gate if (prev == NULL) 19140Sstevel@tonic-gate arrowp->constraints = newc; 19150Sstevel@tonic-gate else 19160Sstevel@tonic-gate prev->next = newc; 19170Sstevel@tonic-gate 19180Sstevel@tonic-gate return (newc); 19190Sstevel@tonic-gate } 19200Sstevel@tonic-gate 19210Sstevel@tonic-gate struct constraintlist * 19220Sstevel@tonic-gate itree_next_constraint(struct arrow *arrowp, struct constraintlist *last) 19230Sstevel@tonic-gate { 19240Sstevel@tonic-gate struct constraintlist *next; 19250Sstevel@tonic-gate 19260Sstevel@tonic-gate if (last != NULL) 19270Sstevel@tonic-gate next = last->next; 19280Sstevel@tonic-gate else 19290Sstevel@tonic-gate next = arrowp->constraints; 19300Sstevel@tonic-gate return (next); 19310Sstevel@tonic-gate } 19320Sstevel@tonic-gate 19330Sstevel@tonic-gate static void 19340Sstevel@tonic-gate itree_free_constraints(struct arrow *ap) 19350Sstevel@tonic-gate { 19360Sstevel@tonic-gate struct constraintlist *cl, *ncl; 19370Sstevel@tonic-gate 19380Sstevel@tonic-gate cl = ap->constraints; 19390Sstevel@tonic-gate while (cl != NULL) { 19400Sstevel@tonic-gate ncl = cl->next; 19410Sstevel@tonic-gate ASSERT(cl->cnode != NULL); 19421414Scindi if (!iexpr_cached(cl->cnode)) 19431414Scindi tree_free(cl->cnode); 19441865Sdilpreet else 19451865Sdilpreet iexpr_free(cl->cnode); 1946*4436Sstephh alloc_xfree(cl, sizeof (*cl)); 19470Sstevel@tonic-gate cl = ncl; 19480Sstevel@tonic-gate } 19490Sstevel@tonic-gate } 19500Sstevel@tonic-gate 19510Sstevel@tonic-gate const char * 19520Sstevel@tonic-gate itree_bubbletype2str(enum bubbletype t) 19530Sstevel@tonic-gate { 19540Sstevel@tonic-gate static char buf[100]; 19550Sstevel@tonic-gate 19560Sstevel@tonic-gate switch (t) { 19570Sstevel@tonic-gate case B_FROM: return L_from; 19580Sstevel@tonic-gate case B_TO: return L_to; 19590Sstevel@tonic-gate case B_INHIBIT: return L_inhibit; 19600Sstevel@tonic-gate default: 19610Sstevel@tonic-gate (void) sprintf(buf, "[unexpected bubbletype: %d]", t); 19620Sstevel@tonic-gate return (buf); 19630Sstevel@tonic-gate } 19640Sstevel@tonic-gate } 19650Sstevel@tonic-gate 19660Sstevel@tonic-gate /* 19670Sstevel@tonic-gate * itree_fini -- clean up any half-built itrees 19680Sstevel@tonic-gate */ 19690Sstevel@tonic-gate void 19700Sstevel@tonic-gate itree_fini(void) 19710Sstevel@tonic-gate { 19720Sstevel@tonic-gate if (Ninfo.lut != NULL) { 19730Sstevel@tonic-gate itree_free(Ninfo.lut); 19740Sstevel@tonic-gate Ninfo.lut = NULL; 19750Sstevel@tonic-gate } 19760Sstevel@tonic-gate if (Ninfo.ex) { 19770Sstevel@tonic-gate lut_free(Ninfo.ex, iterinfo_destructor, NULL); 19780Sstevel@tonic-gate Ninfo.ex = NULL; 19790Sstevel@tonic-gate } 19800Sstevel@tonic-gate } 1981