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