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