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