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