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