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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
26 * itree.c -- instance tree creation and manipulation
28 * this module provides the instance tree
49 * struct info contains the state we keep when expanding a prop statement
50 * as part of constructing the instance tree. state kept in struct info
51 * is the non-recursive stuff -- the stuff that doesn't need to be on
52 * the stack. the rest of the state that is passed between all the
53 * mutually recursive functions, is required to be on the stack since
54 * we need to backtrack and recurse as we do the instance tree construction.
58 struct node
*anp
; /* arrow np */
59 struct lut
*ex
; /* dictionary of explicit iterators */
64 * struct wildcardinfo is used to track wildcarded portions of paths.
66 * for example, if the epname of an event is "c/d" and the path "a/b/c/d"
67 * exists, the wildcard path ewname is filled in with the path "a/b". when
68 * matching is done, epname is temporarily replaced with the concatenation
69 * of ewname and epname.
71 * a linked list of these structs is used to track the expansion of each
72 * event node as it is processed in vmatch() --> vmatch_event() calls.
75 struct node
*nptop
; /* event node fed to vmatch */
76 struct node
*oldepname
; /* epname without the wildcard part */
77 struct node
*ewname
; /* wildcard path */
79 struct wildcardinfo
*next
;
82 static struct wildcardinfo
*wcproot
= NULL
;
84 static void vmatch(struct info
*infop
, struct node
*np
, struct node
*lnp
,
86 static void hmatch(struct info
*infop
, struct node
*np
, struct node
*nextnp
);
87 static void hmatch_event(struct info
*infop
, struct node
*eventnp
,
88 struct node
*epname
, struct config
*ncp
, struct node
*nextnp
, int rematch
);
89 static void itree_pbubble(int flags
, struct bubble
*bp
);
90 static void itree_pruner(void *left
, void *right
, void *arg
);
91 static void itree_destructor(void *left
, void *right
, void *arg
);
92 static int itree_set_arrow_traits(struct arrow
*ap
, struct node
*fromev
,
93 struct node
*toev
, struct lut
*ex
);
94 static void itree_free_arrowlists(struct bubble
*bubp
, int arrows_too
);
95 static void itree_prune_arrowlists(struct bubble
*bubp
);
96 static void arrow_add_within(struct arrow
*ap
, struct node
*xpr
);
97 static struct arrow
*itree_add_arrow(struct node
*apnode
,
98 struct node
*fromevent
, struct node
*toevent
, struct lut
*ex
);
99 static struct event
*find_or_add_event(struct info
*infop
, struct node
*np
);
100 static void add_arrow(struct bubble
*bp
, struct arrow
*ap
);
101 static struct constraintlist
*itree_add_constraint(struct arrow
*arrowp
,
103 static struct bubble
*itree_add_bubble(struct event
*eventp
,
104 enum bubbletype btype
, int nork
, int gen
);
105 static void itree_free_bubble(struct bubble
*freeme
);
106 static void itree_free_constraints(struct arrow
*ap
);
109 * the following struct contains the state we build up during
110 * vertical and horizontal expansion so that generate()
111 * has everything it needs to construct the appropriate arrows.
112 * after setting up the state by calling:
118 * the actual arrow generation is done by calling:
122 int generation
; /* generation number of arrow set */
123 int matched
; /* number of matches */
124 struct node
*arrownp
; /* top-level parse tree for arrow */
125 int n
; /* n value associated with arrow */
126 int k
; /* k value associated with arrow */
127 struct node
*fromnp
; /* left-hand-side event in parse tree */
128 struct node
*tonp
; /* right-hand-side event in parse tree */
129 struct event
*frome
; /* left-hand-side event in instance tree */
130 struct event
*toe
; /* right-hand-side event in instance tree */
131 struct bubble
*frombp
; /* bubble arrow comes from */
132 struct bubble
*tobp
; /* bubble arrow goes to */
136 generate_arrownp(struct node
*arrownp
)
142 generate_nork(int n
, int k
)
155 generate_from(struct node
*fromeventnp
)
158 G
.fromnp
= fromeventnp
;
162 generate_to(struct node
*toeventnp
)
168 generate(struct info
*infop
)
170 struct arrow
*arrowp
;
172 ASSERT(G
.arrownp
!= NULL
);
173 ASSERT(G
.fromnp
!= NULL
);
174 ASSERT(G
.tonp
!= NULL
);
176 out(O_ALTFP
|O_VERB3
|O_NONL
, " Arrow \"");
177 ptree_name_iter(O_ALTFP
|O_VERB3
|O_NONL
, G
.fromnp
);
178 out(O_ALTFP
|O_VERB3
|O_NONL
, "\" -> \"");
179 ptree_name_iter(O_ALTFP
|O_VERB3
|O_NONL
, G
.tonp
);
180 out(O_ALTFP
|O_VERB3
|O_NONL
, "\" ");
182 arrowp
= itree_add_arrow(G
.arrownp
, G
.fromnp
, G
.tonp
, infop
->ex
);
183 if (arrowp
== NULL
) {
184 out(O_ALTFP
|O_VERB3
, "(prevented by constraints)");
186 out(O_ALTFP
|O_VERB3
, "");
188 G
.frome
= find_or_add_event(infop
, G
.fromnp
);
189 G
.frombp
= itree_add_bubble(G
.frome
, B_FROM
, G
.n
, 0);
191 G
.toe
= find_or_add_event(infop
, G
.tonp
);
192 G
.tobp
= itree_add_bubble(G
.toe
, B_TO
, G
.k
, G
.generation
);
193 arrowp
->tail
= G
.frombp
;
194 arrowp
->head
= G
.tobp
;
195 add_arrow(G
.frombp
, arrowp
);
196 add_arrow(G
.tobp
, arrowp
);
200 enum childnode_action
{
206 tname_dup(struct node
*namep
, enum childnode_action act
)
208 struct node
*retp
= NULL
;
218 for (; namep
!= NULL
; namep
= namep
->u
.name
.next
) {
219 struct node
*newnp
= newnode(T_NAME
, file
, line
);
221 newnp
->u
.name
.t
= namep
->u
.name
.t
;
222 newnp
->u
.name
.s
= namep
->u
.name
.s
;
223 newnp
->u
.name
.last
= newnp
;
224 newnp
->u
.name
.it
= namep
->u
.name
.it
;
225 newnp
->u
.name
.cp
= namep
->u
.name
.cp
;
230 npc
= namep
->u
.name
.child
;
234 newnp
->u
.name
.child
=
235 newnode(T_NUM
, file
, line
);
236 newnp
->u
.name
.child
->u
.ull
=
240 newnp
->u
.name
.child
=
241 tree_name(npc
->u
.name
.s
,
242 npc
->u
.name
.it
, file
, line
);
245 out(O_DIE
, "tname_dup: "
246 "invalid child type %s",
247 ptree_nodetype2str(npc
->t
));
255 retp
->u
.name
.last
->u
.name
.next
= newnp
;
256 retp
->u
.name
.last
= newnp
;
263 struct prop_wlk_data
{
268 static struct lut
*props2instance(struct node
*, struct node
*);
271 * let oldepname be a subset of epname. return the subsection of epname
272 * that ends with oldepname. make each component in the path explicitly
273 * instanced (i.e., with a T_NUM child).
276 tname_dup_to_epname(struct node
*oldepname
, struct node
*epname
)
278 struct node
*npref
, *npend
, *np1
, *np2
;
279 struct node
*ret
= NULL
;
286 * search for the longest path in epname which contains
287 * oldnode->u.event.epname. set npend to point to just past the
291 for (npref
= epname
; npref
; npref
= npref
->u
.name
.next
) {
292 if (npref
->u
.name
.s
== oldepname
->u
.name
.s
) {
293 for (np1
= npref
, np2
= oldepname
;
294 np1
!= NULL
&& np2
!= NULL
;
295 np1
= np1
->u
.name
.next
, np2
= np2
->u
.name
.next
) {
296 if (np1
->u
.name
.s
!= np2
->u
.name
.s
)
303 /* oldepname matched npref up to end */
310 if (foundmatch
== 0) {
312 * if oldepname could not be found in epname, return a
313 * duplicate of the former. do not try to instantize
314 * oldepname since it might not be a path.
316 return (tname_dup(oldepname
, CN_DUP
));
320 * dup (epname -- npend). all children should be T_NUMs.
323 ! (npref
== NULL
|| npref
== npend
);
324 npref
= npref
->u
.name
.next
) {
325 struct node
*newnp
= newnode(T_NAME
, oldepname
->file
,
328 newnp
->u
.name
.t
= npref
->u
.name
.t
;
329 newnp
->u
.name
.s
= npref
->u
.name
.s
;
330 newnp
->u
.name
.last
= newnp
;
331 newnp
->u
.name
.it
= npref
->u
.name
.it
;
332 newnp
->u
.name
.cp
= npref
->u
.name
.cp
;
334 newnp
->u
.name
.child
= newnode(T_NUM
, oldepname
->file
,
337 if (npref
->u
.name
.child
== NULL
||
338 npref
->u
.name
.child
->t
!= T_NUM
) {
341 ASSERT(npref
->u
.name
.cp
!= NULL
);
342 config_getcompname(npref
->u
.name
.cp
, NULL
, &childnum
);
343 newnp
->u
.name
.child
->u
.ull
= childnum
;
345 newnp
->u
.name
.child
->u
.ull
=
346 npref
->u
.name
.child
->u
.ull
;
352 ret
->u
.name
.last
->u
.name
.next
= newnp
;
353 ret
->u
.name
.last
= newnp
;
361 * restriction: oldnode->u.event.epname has to be equivalent to or a subset
365 tevent_dup_to_epname(struct node
*oldnode
, struct node
*epname
)
369 ret
= newnode(T_EVENT
, oldnode
->file
, oldnode
->line
);
370 ret
->u
.event
.ename
= tname_dup(oldnode
->u
.event
.ename
, CN_NONE
);
371 ret
->u
.event
.epname
= tname_dup_to_epname(oldnode
->u
.event
.epname
,
377 nv_instantiate(void *name
, void *val
, void *arg
)
379 struct prop_wlk_data
*pd
= (struct prop_wlk_data
*)arg
;
380 struct node
*orhs
= (struct node
*)val
;
383 /* handle engines by instantizing the entire engine */
384 if (name
== L_engine
) {
385 ASSERT(orhs
->t
== T_EVENT
);
386 ASSERT(orhs
->u
.event
.ename
->u
.name
.t
== N_SERD
);
388 /* there are only SERD engines for now */
390 nrhs
= newnode(T_SERD
, orhs
->file
, orhs
->line
);
391 nrhs
->u
.stmt
.np
= tevent_dup_to_epname(orhs
, pd
->epname
);
392 nrhs
->u
.stmt
.lutp
= props2instance(orhs
, pd
->epname
);
393 pd
->props
= lut_add(pd
->props
, name
, nrhs
, NULL
);
399 nrhs
= newnode(T_NUM
, orhs
->file
, orhs
->line
);
400 nrhs
->u
.ull
= orhs
->u
.ull
;
401 pd
->props
= lut_add(pd
->props
, name
, nrhs
, NULL
);
404 nrhs
= newnode(T_TIMEVAL
, orhs
->file
, orhs
->line
);
405 nrhs
->u
.ull
= orhs
->u
.ull
;
406 pd
->props
= lut_add(pd
->props
, name
, nrhs
, NULL
);
409 nrhs
= tname_dup_to_epname(orhs
, pd
->epname
);
410 pd
->props
= lut_add(pd
->props
, name
, nrhs
, NULL
);
413 nrhs
= tevent_dup_to_epname(orhs
, pd
->epname
);
414 pd
->props
= lut_add(pd
->props
, name
, nrhs
, NULL
);
417 nrhs
= newnode(T_GLOBID
, orhs
->file
, orhs
->line
);
418 nrhs
->u
.globid
.s
= orhs
->u
.globid
.s
;
419 pd
->props
= lut_add(pd
->props
, name
, nrhs
, NULL
);
422 /* for T_FUNC, we don't duplicate it, just point to node */
423 pd
->props
= lut_add(pd
->props
, name
, orhs
, NULL
);
426 out(O_DIE
, "unexpected nvpair value type %s",
427 ptree_nodetype2str(((struct node
*)val
)->t
));
432 props2instance(struct node
*eventnp
, struct node
*epname
)
434 struct prop_wlk_data pd
;
439 ASSERT(eventnp
->u
.event
.declp
!= NULL
);
440 lut_walk(eventnp
->u
.event
.declp
->u
.stmt
.lutp
, nv_instantiate
, &pd
);
446 instances_destructor(void *left
, void *right
, void *arg
)
448 struct node
*dn
= (struct node
*)right
;
450 if (dn
->t
== T_SERD
) {
451 /* we allocated the lut during itree_create(), so free it */
452 lut_free(dn
->u
.stmt
.lutp
, instances_destructor
, NULL
);
453 dn
->u
.stmt
.lutp
= NULL
;
455 if (dn
->t
!= T_FUNC
) /* T_FUNC pointed to original node */
461 payloadprops_destructor(void *left
, void *right
, void *arg
)
468 serdprops_destructor(void *left
, void *right
, void *arg
)
474 * event_cmp -- used via lut_lookup/lut_add on instance tree lut
477 event_cmp(struct event
*ep1
, struct event
*ep2
)
481 if ((diff
= ep2
->enode
->u
.event
.ename
->u
.name
.s
-
482 ep1
->enode
->u
.event
.ename
->u
.name
.s
) != 0)
484 if ((diff
= (char *)ep2
->ipp
- (char *)ep1
->ipp
) != 0)
491 itree_lookup(struct lut
*itp
, const char *ename
, const struct ipath
*ipp
)
493 struct event searchevent
; /* just used for searching */
494 struct node searcheventnode
;
495 struct node searchenamenode
;
497 searchevent
.enode
= &searcheventnode
;
498 searcheventnode
.t
= T_EVENT
;
499 searcheventnode
.u
.event
.ename
= &searchenamenode
;
500 searchenamenode
.t
= T_NAME
;
501 searchenamenode
.u
.name
.s
= ename
;
502 searchevent
.ipp
= ipp
;
503 return (lut_lookup(itp
, (void *)&searchevent
, (lut_cmp
)event_cmp
));
506 static struct event
*
507 find_or_add_event(struct info
*infop
, struct node
*np
)
510 struct event searchevent
; /* just used for searching */
512 ASSERTeq(np
->t
, T_EVENT
, ptree_nodetype2str
);
514 searchevent
.enode
= np
;
515 searchevent
.ipp
= ipath(np
->u
.event
.epname
);
516 if ((ret
= lut_lookup(infop
->lut
, (void *)&searchevent
,
517 (lut_cmp
)event_cmp
)) != NULL
)
520 /* wasn't already in tree, allocate it */
521 ret
= alloc_xmalloc(sizeof (*ret
));
522 bzero(ret
, sizeof (*ret
));
524 ret
->t
= np
->u
.event
.ename
->u
.name
.t
;
526 ret
->ipp
= searchevent
.ipp
;
527 ret
->props
= props2instance(np
, np
->u
.event
.epname
);
529 infop
->lut
= lut_add(infop
->lut
, (void *)ret
, (void *)ret
,
536 * Used for handling expansions where first part of oldepname is a horizontal
537 * expansion. Recurses through entire tree. oldepname argument is always the
538 * full path as in the rules. Once we find a match we go back to using
539 * hmatch_event to handle the rest.
542 hmatch_full_config(struct info
*infop
, struct node
*eventnp
,
543 struct node
*oldepname
, struct config
*ncp
, struct node
*nextnp
,
544 struct iterinfo
*iterinfop
)
549 struct node
*saved_ewname
;
550 struct node
*saved_epname
;
551 struct config
*pcp
, *ocp
;
553 struct node
*ewlp
, *ewfp
;
555 for (cp
= ncp
; cp
; cp
= config_next(cp
)) {
556 config_getcompname(cp
, &cp_s
, &cp_num
);
557 if (cp_s
== oldepname
->u
.name
.s
) {
561 iterinfop
->num
= cp_num
;
564 * Need to set ewname, epname for correct node as is
565 * needed by constraint path matching. This code is
566 * similar to that in vmatch_event.
568 saved_ewname
= eventnp
->u
.event
.ewname
;
569 saved_epname
= eventnp
->u
.event
.epname
;
570 ocp
= oldepname
->u
.name
.cp
;
573 * Find correct ewname by walking back up the config
574 * tree adding each name portion as we go.
576 pcp
= config_parent(cp
);
577 eventnp
->u
.event
.ewname
= NULL
;
578 for (; pcp
!= infop
->croot
; pcp
= config_parent(pcp
)) {
579 config_getcompname(pcp
, &cp_s
, &cp_num
);
580 cpnode
= tree_name(cp_s
, IT_NONE
, NULL
, 0);
581 cpnode
->u
.name
.child
= newnode(T_NUM
, NULL
, 0);
582 cpnode
->u
.name
.child
->u
.ull
= cp_num
;
583 cpnode
->u
.name
.cp
= pcp
;
584 if (eventnp
->u
.event
.ewname
!= NULL
) {
585 cpnode
->u
.name
.next
=
586 eventnp
->u
.event
.ewname
;
587 cpnode
->u
.name
.last
=
588 eventnp
->u
.event
.ewname
->
591 eventnp
->u
.event
.ewname
= cpnode
;
595 * Now create correct epname by duping new ewname
596 * and appending oldepname.
598 ewfp
= tname_dup(eventnp
->u
.event
.ewname
, CN_DUP
);
599 ewlp
= ewfp
->u
.name
.last
;
600 ewfp
->u
.name
.last
= oldepname
->u
.name
.last
;
601 ewlp
->u
.name
.next
= oldepname
;
602 oldepname
->u
.name
.cp
= cp
;
603 eventnp
->u
.event
.epname
= ewfp
;
605 outfl(O_ALTFP
|O_VERB3
|O_NONL
, infop
->anp
->file
,
606 infop
->anp
->line
, "hmatch_full_config: ");
607 ptree_name_iter(O_ALTFP
|O_VERB3
|O_NONL
,
608 eventnp
->u
.event
.epname
);
609 out(O_ALTFP
|O_VERB3
, NULL
);
612 * Now complete hmatch.
614 hmatch_event(infop
, eventnp
, oldepname
->u
.name
.next
,
615 config_child(cp
), nextnp
, 1);
618 * set everything back again
620 oldepname
->u
.name
.cp
= ocp
;
622 ewlp
->u
.name
.next
= NULL
;
623 ewfp
->u
.name
.last
= ewlp
;
625 tree_free(eventnp
->u
.event
.ewname
);
626 eventnp
->u
.event
.ewname
= saved_ewname
;
627 eventnp
->u
.event
.epname
= saved_epname
;
630 * Try the next level down.
632 hmatch_full_config(infop
, eventnp
,
633 oldepname
, config_child(cp
), nextnp
, iterinfop
);
638 * hmatch_event -- perform any appropriate horizontal expansion on an event
640 * this routine is used to perform horizontal expansion on both the
641 * left-hand-side events in a prop, and the right-hand-side events.
642 * when called to handle a left-side event, nextnp point to the right
643 * side of the prop that should be passed to hmatch() for each match
644 * found by horizontal expansion. when no horizontal expansion exists,
645 * we will still "match" one event for every event found in the list on
646 * the left-hand-side of the prop because vmatch() already found that
647 * there's at least one match during vertical expansion.
650 hmatch_event(struct info
*infop
, struct node
*eventnp
, struct node
*epname
,
651 struct config
*ncp
, struct node
*nextnp
, int rematch
)
653 if (epname
== NULL
) {
655 * end of pathname recursion, either we just located
656 * a left-hand-side event and we're ready to move on
657 * to the expanding the right-hand-side events, or
658 * we're further down the recursion and we just located
659 * a right-hand-side event. the passed-in parameter
660 * "nextnp" tells us whether we're working on the left
661 * side and need to move on to nextnp, or if nextnp is
662 * NULL, we're working on the right side.
666 * finished a left side expansion, move on to right.
667 * tell generate() what event we just matched so
668 * it can be used at the source of any arrows
669 * we generate as we match events on the right side.
671 generate_from(eventnp
);
672 hmatch(infop
, nextnp
, NULL
);
675 * finished a right side expansion. tell generate
676 * the information about the destination and let
677 * it construct the arrows as appropriate.
679 generate_to(eventnp
);
686 ASSERTeq(epname
->t
, T_NAME
, ptree_nodetype2str
);
688 if (epname
->u
.name
.cp
== NULL
)
692 * we only get here when eventnp already has a completely
693 * instanced epname in it already. so we first recurse
694 * down to the end of the name and as the recursion pops
695 * up, we look for opportunities to advance horizontal
696 * expansions on to the next match.
698 if (epname
->u
.name
.it
== IT_HORIZONTAL
|| rematch
) {
700 struct config
*ocp
= epname
->u
.name
.cp
;
704 struct iterinfo
*iterinfop
= NULL
;
708 if (epname
->u
.name
.it
!= IT_HORIZONTAL
) {
710 * Ancestor was horizontal though, so must rematch
711 * against the name/num found in vmatch.
713 config_getcompname(ocp
, NULL
, &ocp_num
);
715 iters
= epname
->u
.name
.child
->u
.name
.s
;
716 if ((iterinfop
= lut_lookup(infop
->ex
,
717 (void *)iters
, NULL
)) == NULL
) {
719 * do horizontal expansion on this node
722 iterinfop
= alloc_xmalloc(
723 sizeof (struct iterinfo
));
725 iterinfop
->np
= epname
;
726 infop
->ex
= lut_add(infop
->ex
, (void *)iters
,
728 } else if (iterinfop
->num
== -1) {
732 * This name has already been used in a
733 * horizontal expansion. This time just match it
735 ocp_num
= iterinfop
->num
;
739 * handle case where this is the first section of oldepname
740 * and it is horizontally expanded. Instead of just looking for
741 * siblings, we want to scan the entire config tree for further
744 if (epname
== eventnp
->u
.event
.oldepname
&&
745 epname
->u
.name
.it
== IT_HORIZONTAL
) {
747 * Run through config looking for any that match the
750 hmatch_full_config(infop
, eventnp
, epname
,
751 infop
->croot
, nextnp
, iterinfop
);
756 * Run through siblings looking for any that match the name.
757 * If hexpand not set then num must also match ocp_num.
759 for (cp
= rematch
? ncp
: ocp
; cp
; cp
= config_next(cp
)) {
760 config_getcompname(cp
, &cp_s
, &cp_num
);
761 if (cp_s
== epname
->u
.name
.s
) {
763 iterinfop
->num
= cp_num
;
764 else if (ocp_num
!= cp_num
)
766 epname
->u
.name
.cp
= cp
;
767 hmatch_event(infop
, eventnp
,
768 epname
->u
.name
.next
, config_child(cp
),
772 epname
->u
.name
.cp
= ocp
;
776 hmatch_event(infop
, eventnp
, epname
->u
.name
.next
,
782 * hmatch -- check for horizontal expansion matches
784 * np points to the things we're matching (like a T_LIST or a T_EVENT)
785 * and if we're working on a left-side of a prop, nextnp points to
786 * the other side of the prop that we'll tackle next when this recursion
787 * bottoms out. when all the events in the entire prop arrow have been
788 * horizontally expanded, generate() will be called to generate the
792 hmatch(struct info
*infop
, struct node
*np
, struct node
*nextnp
)
795 return; /* all done */
798 * for each item in the list of events (which could just
799 * be a single event, or it could get larger in the loop
800 * below due to horizontal expansion), call hmatch on
801 * the right side and create arrows to each element.
806 /* loop through the list */
808 hmatch(infop
, np
->u
.expr
.left
, nextnp
);
809 if (np
->u
.expr
.right
)
810 hmatch(infop
, np
->u
.expr
.right
, nextnp
);
814 hmatch_event(infop
, np
, np
->u
.event
.epname
,
819 outfl(O_DIE
, np
->file
, np
->line
,
820 "hmatch: unexpected type: %s",
821 ptree_nodetype2str(np
->t
));
826 itree_np2nork(struct node
*norknp
)
830 else if (norknp
->t
== T_NAME
&& norknp
->u
.name
.s
== L_A
)
831 return (-1); /* our internal version of "all" */
832 else if (norknp
->t
== T_NUM
)
833 return ((int)norknp
->u
.ull
);
835 outfl(O_DIE
, norknp
->file
, norknp
->line
,
836 "itree_np2nork: internal error type %s",
837 ptree_nodetype2str(norknp
->t
));
842 static struct iterinfo
*
843 newiterinfo(int num
, struct node
*np
)
845 struct iterinfo
*ret
= alloc_xmalloc(sizeof (*ret
));
854 iterinfo_destructor(void *left
, void *right
, void *arg
)
856 struct iterinfo
*iterinfop
= (struct iterinfo
*)right
;
858 alloc_xfree(iterinfop
, sizeof (*iterinfop
));
862 vmatch_event(struct info
*infop
, struct config
*cp
, struct node
*np
,
863 struct node
*lnp
, struct node
*anp
, struct wildcardinfo
*wcp
)
867 struct node
*ewlp
, *ewfp
;
873 * handle case where the first section of the path name is horizontally
874 * expanded. The whole expansion is handled by hmatch on the first
875 * match here - so we just skip any subsequent matches here.
877 if (wcp
->got_wc_hz
== 1)
882 * Reached the end of the name. u.name.cp pointers should be set
883 * up for each part of name. From this we can use config tree
884 * to build up the wildcard part of the name (if any).
886 pcp
= config_parent(wcp
->nptop
->u
.event
.epname
->u
.name
.cp
);
887 if (pcp
== infop
->croot
) {
889 * no wildcarding done - move on to next entry
891 wcp
->nptop
->u
.event
.ewname
= wcp
->ewname
;
892 wcp
->nptop
->u
.event
.oldepname
= wcp
->oldepname
;
893 vmatch(infop
, np
, lnp
, anp
);
897 if (wcp
->ewname
== NULL
) {
899 * ewname not yet set up - do it now
902 for (; pcp
!= infop
->croot
; pcp
= config_parent(pcp
)) {
903 config_getcompname(pcp
, &cp_s
, &cp_num
);
904 cpnode
= tree_name(cp_s
, IT_NONE
, NULL
, 0);
905 cpnode
->u
.name
.child
= newnode(T_NUM
, NULL
, 0);
906 cpnode
->u
.name
.child
->u
.ull
= cp_num
;
907 cpnode
->u
.name
.cp
= pcp
;
908 if (wcp
->ewname
!= NULL
) {
909 cpnode
->u
.name
.next
= wcp
->ewname
;
910 cpnode
->u
.name
.last
=
911 wcp
->ewname
->u
.name
.last
;
913 wcp
->ewname
= cpnode
;
918 * dup ewname and append oldepname
920 ewfp
= tname_dup(wcp
->ewname
, CN_DUP
);
921 ewlp
= ewfp
->u
.name
.last
;
922 ewfp
->u
.name
.last
= wcp
->oldepname
->u
.name
.last
;
923 ewlp
->u
.name
.next
= wcp
->oldepname
;
925 wcp
->nptop
->u
.event
.epname
= ewfp
;
926 wcp
->nptop
->u
.event
.ewname
= wcp
->ewname
;
927 wcp
->nptop
->u
.event
.oldepname
= wcp
->oldepname
;
928 vmatch(infop
, np
, lnp
, anp
);
930 wcp
->nptop
->u
.event
.epname
= wcp
->oldepname
;
933 * reduce duped ewname to original then free
935 ewlp
->u
.name
.next
= NULL
;
936 ewfp
->u
.name
.last
= ewlp
;
941 * free ewname if allocated above
943 tree_free(wcp
->ewname
);
950 * We have an np. See if we can match it in this section of
954 return; /* no more config to match against */
956 for (; cp
; cp
= config_next(cp
)) {
957 config_getcompname(cp
, &cp_s
, &cp_num
);
959 if (cp_s
== np
->u
.name
.s
) {
960 /* found a matching component name */
961 if (np
->u
.name
.child
&&
962 np
->u
.name
.child
->t
== T_NUM
) {
964 * an explicit instance number was given
965 * in the source. so only consider this
966 * a configuration match if the number
969 if (cp_num
!= np
->u
.name
.child
->u
.ull
)
972 } else if (np
->u
.name
.it
!= IT_HORIZONTAL
) {
973 struct iterinfo
*iterinfop
;
977 * vertical iterator. look it up in
978 * the appropriate lut and if we get
979 * back a value it is either one that we
980 * set earlier, in which case we record
981 * the new value for this iteration and
982 * keep matching, or it is one that was
983 * set by an earlier reference to the
984 * iterator, in which case we only consider
985 * this a configuration match if the number
989 ASSERT(np
->u
.name
.child
!= NULL
);
990 ASSERT(np
->u
.name
.child
->t
== T_NAME
);
991 iters
= np
->u
.name
.child
->u
.name
.s
;
993 if ((iterinfop
= lut_lookup(infop
->ex
,
994 (void *)iters
, NULL
)) == NULL
) {
995 /* we're the first use, record our np */
996 infop
->ex
= lut_add(infop
->ex
,
998 newiterinfo(cp_num
, np
), NULL
);
999 } else if (np
== iterinfop
->np
) {
1001 * we're the first use, back again
1002 * for another iteration. so update
1003 * the num bound to this iterator in
1006 iterinfop
->num
= cp_num
;
1007 } else if (cp_num
!= iterinfop
->num
) {
1009 * an earlier reference to this
1010 * iterator bound it to a different
1011 * instance number, so there's no
1012 * match here after all.
1014 * however, it's possible that this
1015 * component should really be part of
1016 * the wildcard. we explore this by
1017 * forcing this component into the
1018 * wildcarded section.
1020 * for an more details of what's
1021 * going to happen now, see
1022 * comments block below entitled
1023 * "forcing components into
1026 if (np
== wcp
->nptop
->u
.event
.epname
)
1028 config_child(cp
), np
, lnp
,
1035 * if this was an IT_HORIZONTAL name, hmatch() will
1036 * expand all matches horizontally into a list.
1037 * we know the list will contain at least
1038 * one element (the one we just matched),
1039 * so we just let hmatch_event() do the rest.
1041 * recurse on to next component. Note that
1042 * wildcarding is now turned off.
1045 vmatch_event(infop
, config_child(cp
), np
->u
.name
.next
,
1047 np
->u
.name
.cp
= NULL
;
1050 * handle case where this is the first section of the
1051 * path name and it is horizontally expanded.
1052 * In this case we want all matching nodes in the config
1053 * to be expanded horizontally - so set got_wc_hz and
1054 * leave all further processing to hmatch.
1056 if (G
.matched
&& np
== wcp
->nptop
->u
.event
.epname
&&
1057 np
->u
.name
.it
== IT_HORIZONTAL
)
1061 * forcing components into wildcard path:
1063 * if this component is the first match, force it
1064 * to be part of the wildcarded path and see if we
1065 * can get additional matches.
1067 * here's an example. suppose we have the
1073 * the code up to this point will treat "a0" as the
1074 * wildcarded part of the path and "x0/y0" as the
1075 * nonwildcarded part, resulting in the instanced
1079 * in order to discover the next match (.../x1/y1)
1080 * in the configuration we have to force "x0" into
1081 * the wildcarded part of the path.
1082 * by doing so, we discover the wildcarded part
1083 * "a0/x0/y0/a1" and the nonwildcarded part "x1/y1"
1085 * the following call to vmatch_event() is also
1086 * needed to properly handle the configuration
1089 * the recursions into vmatch_event() will start
1090 * off uncovering "b0" as the wildcarded part and
1091 * "x0" as the start of the nonwildcarded path.
1092 * however, the next recursion will not result in a
1093 * match since there is no "y" following "x0". the
1094 * subsequent match of (wildcard = "b0/x0/b1" and
1095 * nonwildcard = "x1/y1") will be discovered only
1096 * if "x0" is forced to be a part of the wildcarded
1099 if (np
== wcp
->nptop
->u
.event
.epname
)
1100 vmatch_event(infop
, config_child(cp
), np
, lnp
,
1103 if (np
->u
.name
.it
== IT_HORIZONTAL
) {
1105 * hmatch() finished iterating through
1106 * the configuration as described above, so
1107 * don't continue iterating here.
1111 } else if (np
== wcp
->nptop
->u
.event
.epname
) {
1113 * no match - carry on down the tree looking for
1116 vmatch_event(infop
, config_child(cp
), np
, lnp
, anp
,
1123 * vmatch -- find the next vertical expansion match in the config database
1125 * this routine is called with three node pointers:
1126 * np -- the parse we're matching
1127 * lnp -- the rest of the list we're currently working on
1128 * anp -- the rest of the arrow we're currently working on
1130 * the expansion matching happens via three types of recursion:
1132 * - when given an arrow, handle the left-side and then recursively
1133 * handle the right side (which might be another cascaded arrow).
1135 * - when handling one side of an arrow, recurse through the T_LIST
1136 * to get to each event (or just move on to the event if there
1137 * is a single event instead of a list) since the arrow parse
1138 * trees recurse left, we actually start with the right-most
1139 * event list in the prop statement and work our way towards
1140 * the left-most event list.
1142 * - when handling an event, recurse down each component of the
1143 * pathname, matching in the config database and recording the
1144 * matches in the explicit iterator dictionary as we go.
1146 * when the bottom of this matching recursion is met, meaning we have
1147 * set the "cp" pointers on all the names in the entire statement,
1148 * we call hmatch() which does it's own recursion to handle horizontal
1149 * expandsion and then call generate() to generate nodes, bubbles, and
1150 * arrows in the instance tree. generate() looks at the cp pointers to
1151 * see what instance numbers were matched in the configuration database.
1153 * when horizontal expansion appears, vmatch() finds only the first match
1154 * and hmatch() then takes the horizontal expansion through all the other
1155 * matches when generating the arrows in the instance tree.
1157 * the "infop" passed down through the recursion contains a dictionary
1158 * of the explicit iterators (all the implicit iterators have been converted
1159 * to explicit iterators when the parse tree was created by tree.c), which
1160 * allows things like this to work correctly:
1162 * prop error.a@x[n]/y/z -> error.b@x/y[n]/z -> error.c@x/y/z[n];
1164 * during the top level call, the explicit iterator "n" will match an
1165 * instance number in the config database, and the result will be recorded
1166 * in the explicit iterator dictionary and passed down via "infop". so
1167 * when the recursive call tries to match y[n] in the config database, it
1168 * will only match the same instance number as x[n] did since the dictionary
1169 * is consulted to see if "n" took on a value already.
1171 * at any point during the recursion, match*() can return to indicate
1172 * a match was not found in the config database and that the caller should
1173 * move on to the next potential match, if any.
1175 * constraints are completely ignored by match(), so the statement:
1177 * prop error.a@x[n] -> error.b@x[n] {n != 0};
1179 * might very well match x[0] if it appears in the config database. it
1180 * is the generate() routine that takes that match and then decides what
1181 * arrow, if any, should be generated in the instance tree. generate()
1182 * looks at the explicit iterator dictionary to get values like "n" in
1183 * the above example so that it can evaluate constraints.
1187 vmatch(struct info
*infop
, struct node
*np
, struct node
*lnp
, struct node
*anp
)
1189 struct node
*np1
, *np2
, *oldepname
, *oldnptop
;
1192 struct wildcardinfo
*wcp
;
1197 vmatch(infop
, lnp
, NULL
, anp
);
1199 vmatch(infop
, anp
, NULL
, NULL
);
1204 /* end of vertical match recursion */
1205 outfl(O_ALTFP
|O_VERB3
|O_NONL
,
1206 infop
->anp
->file
, infop
->anp
->line
, "vmatch: ");
1207 ptree_name_iter(O_ALTFP
|O_VERB3
|O_NONL
, infop
->anp
);
1208 out(O_ALTFP
|O_VERB3
, NULL
);
1211 itree_np2nork(infop
->anp
->u
.arrow
.nnp
),
1212 itree_np2nork(infop
->anp
->u
.arrow
.knp
));
1213 dst
= infop
->anp
->u
.arrow
.rhs
;
1214 src
= infop
->anp
->u
.arrow
.lhs
;
1216 generate_new(); /* new set of arrows */
1217 if (src
->t
== T_ARROW
) {
1218 hmatch(infop
, src
->u
.arrow
.rhs
, dst
);
1220 itree_np2nork(src
->u
.arrow
.nnp
),
1221 itree_np2nork(src
->u
.arrow
.knp
));
1222 dst
= src
->u
.arrow
.rhs
;
1223 src
= src
->u
.arrow
.lhs
;
1225 hmatch(infop
, src
, dst
);
1237 * see if we already have a match in the wcps
1239 for (wcp
= wcproot
; wcp
; wcp
= wcp
->next
) {
1240 oldepname
= wcp
->oldepname
;
1241 oldnptop
= wcp
->nptop
;
1242 for (np1
= oldepname
, np2
= np
->u
.event
.epname
;
1243 np1
!= NULL
&& np2
!= NULL
; np1
= np1
->u
.name
.next
,
1244 np2
= np2
->u
.name
.next
) {
1245 if (strcmp(np1
->u
.name
.s
, np2
->u
.name
.s
) != 0)
1247 if (np1
->u
.name
.child
->t
!=
1248 np2
->u
.name
.child
->t
)
1250 if (np1
->u
.name
.child
->t
== T_NUM
&&
1251 np1
->u
.name
.child
->u
.ull
!=
1252 np2
->u
.name
.child
->u
.ull
)
1254 if (np1
->u
.name
.child
->t
== T_NAME
&&
1255 strcmp(np1
->u
.name
.child
->u
.name
.s
,
1256 np2
->u
.name
.child
->u
.name
.s
) != 0)
1263 if (epmatches
&& np1
== NULL
&& np2
== NULL
) {
1265 * complete names match, can just borrow the fields
1267 oldepname
= np
->u
.event
.epname
;
1268 np
->u
.event
.epname
= oldnptop
->u
.event
.epname
;
1269 np
->u
.event
.oldepname
= wcp
->oldepname
;
1270 np
->u
.event
.ewname
= wcp
->ewname
;
1271 vmatch(infop
, NULL
, lnp
, anp
);
1272 np
->u
.event
.epname
= oldepname
;
1278 * just first part of names match - do wildcarding
1279 * by using existing wcp including ewname and also
1280 * copying as much of pwname as is valid, then start
1281 * vmatch_event() at start of non-matching section
1283 for (np1
= oldepname
, np2
= np
->u
.event
.epname
;
1284 epmatches
!= 0; epmatches
--) {
1285 cp
= np1
->u
.name
.cp
;
1286 np2
->u
.name
.cp
= cp
;
1287 np1
= np1
->u
.name
.next
;
1288 np2
= np2
->u
.name
.next
;
1290 wcp
->oldepname
= np
->u
.event
.epname
;
1292 vmatch_event(infop
, config_child(cp
), np2
, lnp
,
1294 wcp
->oldepname
= oldepname
;
1295 wcp
->nptop
= oldnptop
;
1296 if (G
.matched
== 0) {
1298 * This list entry is NULL. Move on to next item
1301 vmatch(infop
, NULL
, lnp
, anp
);
1306 * names do not match - allocate a new wcp
1308 wcp
= MALLOC(sizeof (struct wildcardinfo
));
1309 wcp
->next
= wcproot
;
1312 wcp
->oldepname
= np
->u
.event
.epname
;
1316 vmatch_event(infop
, config_child(infop
->croot
),
1317 np
->u
.event
.epname
, lnp
, anp
, wcp
);
1319 wcproot
= wcp
->next
;
1321 if (G
.matched
== 0) {
1323 * This list entry is NULL. Move on to next item in the
1326 vmatch(infop
, NULL
, lnp
, anp
);
1331 ASSERT(lnp
== NULL
);
1332 vmatch(infop
, np
->u
.expr
.right
, np
->u
.expr
.left
, anp
);
1336 ASSERT(lnp
== NULL
&& anp
== NULL
);
1337 vmatch(infop
, np
->u
.arrow
.rhs
, NULL
, np
->u
.arrow
.parent
);
1341 outfl(O_DIE
, np
->file
, np
->line
,
1342 "vmatch: unexpected type: %s",
1343 ptree_nodetype2str(np
->t
));
1348 find_first_arrow(struct info
*infop
, struct node
*anp
)
1350 if (anp
->u
.arrow
.lhs
->t
== T_ARROW
) {
1351 anp
->u
.arrow
.lhs
->u
.arrow
.parent
= anp
;
1352 find_first_arrow(infop
, anp
->u
.arrow
.lhs
);
1354 vmatch(infop
, anp
->u
.arrow
.lhs
, NULL
, anp
);
1358 cp_reset(struct node
*np
)
1364 np
->u
.name
.cp
= NULL
;
1365 cp_reset(np
->u
.name
.next
);
1369 cp_reset(np
->u
.expr
.left
);
1370 cp_reset(np
->u
.expr
.right
);
1374 cp_reset(np
->u
.arrow
.lhs
);
1375 cp_reset(np
->u
.arrow
.rhs
);
1379 cp_reset(np
->u
.event
.epname
);
1385 * itree_create -- apply the current config to the current parse tree
1387 * returns a lut mapping fully-instance-qualified names to struct events.
1391 itree_create(struct config
*croot
)
1394 struct node
*propnp
;
1395 extern int alloc_total();
1399 Ninfo
.croot
= croot
;
1400 init_size
= alloc_total();
1401 out(O_ALTFP
|O_STAMP
, "start itree_create using %d bytes", init_size
);
1402 for (propnp
= Props
; propnp
; propnp
= propnp
->u
.stmt
.next
) {
1403 struct node
*anp
= propnp
->u
.stmt
.np
;
1405 ASSERTeq(anp
->t
, T_ARROW
, ptree_nodetype2str
);
1407 if (!anp
->u
.arrow
.needed
)
1412 generate_arrownp(anp
);
1413 anp
->u
.arrow
.parent
= NULL
;
1414 find_first_arrow(&Ninfo
, anp
);
1417 lut_free(Ninfo
.ex
, iterinfo_destructor
, NULL
);
1423 out(O_ALTFP
|O_STAMP
, "itree_create added %d bytes",
1424 alloc_total() - init_size
);
1431 * initial first pass of the rules.
1432 * We don't use the config at all. Just check the last part of the pathname
1433 * in the rules. If this matches the last part of the pathname in the first
1434 * ereport, then set pathname to the pathname in the ereport. If not then
1435 * set pathname to just the last part of pathname with instance number 0.
1436 * Constraints are ignored and all nork values are set to 0. If after all that
1437 * any rules can still not be associated with the ereport, then they are set
1438 * to not needed in prune_propagations() and ignored in the real itree_create()
1442 static struct event
*
1443 add_event_dummy(struct node
*np
, const struct ipath
*ipp
)
1446 struct event searchevent
; /* just used for searching */
1447 extern struct ipath
*ipath_dummy(struct node
*, struct ipath
*);
1448 struct ipath
*ipp_un
;
1449 extern struct ipath
*ipath_for_usednames(struct node
*);
1451 searchevent
.enode
= np
;
1452 searchevent
.ipp
= ipath_dummy(np
->u
.event
.epname
, (struct ipath
*)ipp
);
1453 ipp_un
= ipath_for_usednames(np
->u
.event
.epname
);
1454 if ((ret
= lut_lookup(Ninfo
.lut
, (void *)&searchevent
,
1455 (lut_cmp
)event_cmp
)) != NULL
)
1458 ret
= alloc_xmalloc(sizeof (*ret
));
1459 bzero(ret
, sizeof (*ret
));
1460 ret
->t
= np
->u
.event
.ename
->u
.name
.t
;
1462 ret
->ipp
= searchevent
.ipp
;
1463 ret
->ipp_un
= ipp_un
;
1464 Ninfo
.lut
= lut_add(Ninfo
.lut
, (void *)ret
, (void *)ret
,
1465 (lut_cmp
)event_cmp
);
1471 itree_create_dummy(const char *e0class
, const struct ipath
*e0ipp
)
1473 struct node
*propnp
;
1474 struct event
*frome
, *toe
;
1475 struct bubble
*frombp
, *tobp
;
1476 struct arrow
*arrowp
;
1477 struct node
*src
, *dst
, *slst
, *dlst
, *arrownp
, *oldarrownp
;
1479 extern int alloc_total();
1483 init_size
= alloc_total();
1484 out(O_ALTFP
|O_STAMP
, "start itree_create using %d bytes", init_size
);
1485 for (propnp
= Props
; propnp
; propnp
= propnp
->u
.stmt
.next
) {
1486 arrownp
= propnp
->u
.stmt
.np
;
1489 dlst
= arrownp
->u
.arrow
.rhs
;
1490 slst
= arrownp
->u
.arrow
.lhs
;
1491 oldarrownp
= arrownp
;
1492 if (slst
->t
== T_ARROW
) {
1494 slst
= slst
->u
.arrow
.rhs
;
1499 if (slst
->t
== T_LIST
) {
1500 src
= slst
->u
.expr
.right
;
1501 slst
= slst
->u
.expr
.left
;
1506 frome
= add_event_dummy(src
, e0ipp
);
1507 frombp
= itree_add_bubble(frome
, B_FROM
, 0, 0);
1509 if (dlst
->t
== T_LIST
) {
1510 dst
= dlst
->u
.expr
.right
;
1511 dlst
= dlst
->u
.expr
.left
;
1516 arrowp
= alloc_xmalloc(
1517 sizeof (struct arrow
));
1518 bzero(arrowp
, sizeof (struct arrow
));
1519 arrowp
->pnode
= oldarrownp
;
1520 toe
= add_event_dummy(dst
, e0ipp
);
1521 tobp
= itree_add_bubble(toe
, B_TO
, 0,
1523 arrowp
->tail
= frombp
;
1524 arrowp
->head
= tobp
;
1525 add_arrow(frombp
, arrowp
);
1526 add_arrow(tobp
, arrowp
);
1527 arrow_add_within(arrowp
,
1528 dst
->u
.event
.declp
->u
.stmt
.np
->
1530 arrow_add_within(arrowp
,
1531 dst
->u
.event
.eexprlist
);
1536 out(O_ALTFP
|O_STAMP
, "itree_create added %d bytes",
1537 alloc_total() - init_size
);
1542 itree_free(struct lut
*lutp
)
1546 init_size
= alloc_total();
1547 out(O_ALTFP
|O_STAMP
, "start itree_free");
1548 lut_free(lutp
, itree_destructor
, NULL
);
1549 out(O_ALTFP
|O_STAMP
, "itree_free freed %d bytes",
1550 init_size
- alloc_total());
1554 itree_prune(struct lut
*lutp
)
1558 init_size
= alloc_total();
1559 out(O_ALTFP
|O_STAMP
, "start itree_prune");
1560 lut_walk(lutp
, itree_pruner
, NULL
);
1561 out(O_ALTFP
|O_STAMP
, "itree_prune freed %d bytes",
1562 init_size
- alloc_total());
1566 itree_pevent_brief(int flags
, struct event
*ep
)
1569 ASSERT(ep
->enode
!= NULL
);
1570 ASSERT(ep
->ipp
!= NULL
);
1572 ipath_print(flags
, ep
->enode
->u
.event
.ename
->u
.name
.s
, ep
->ipp
);
1577 itree_pevent(struct event
*lhs
, struct event
*ep
, void *arg
)
1579 struct plut_wlk_data propd
;
1581 int flags
= (int)(intptr_t)arg
;
1583 itree_pevent_brief(flags
, ep
);
1584 if (ep
->t
== N_EREPORT
)
1585 out(flags
, " (count %d)", ep
->count
);
1590 propd
.flags
= flags
;
1592 out(flags
, "Properties:");
1593 lut_walk(ep
->props
, ptree_plut
, (void *)&propd
);
1596 for (bp
= itree_next_bubble(ep
, NULL
); bp
;
1597 bp
= itree_next_bubble(ep
, bp
)) {
1598 /* Print only TO bubbles in this loop */
1601 itree_pbubble(flags
, bp
);
1604 for (bp
= itree_next_bubble(ep
, NULL
); bp
;
1605 bp
= itree_next_bubble(ep
, bp
)) {
1606 /* Print only INHIBIT bubbles in this loop */
1607 if (bp
->t
!= B_INHIBIT
)
1609 itree_pbubble(flags
, bp
);
1612 for (bp
= itree_next_bubble(ep
, NULL
); bp
;
1613 bp
= itree_next_bubble(ep
, bp
)) {
1614 /* Print only FROM bubbles in this loop */
1615 if (bp
->t
!= B_FROM
)
1617 itree_pbubble(flags
, bp
);
1622 itree_pbubble(int flags
, struct bubble
*bp
)
1624 struct constraintlist
*cp
;
1625 struct arrowlist
*ap
;
1629 out(flags
|O_NONL
, " ");
1631 out(flags
|O_NONL
, "*");
1633 out(flags
|O_NONL
, " ");
1634 if (bp
->t
== B_FROM
)
1635 out(flags
|O_NONL
, "N=%d to:", bp
->nork
);
1636 else if (bp
->t
== B_TO
)
1637 out(flags
|O_NONL
, "K=%d from:", bp
->nork
);
1639 out(flags
|O_NONL
, "K=%d masked from:", bp
->nork
);
1641 if (bp
->t
== B_TO
|| bp
->t
== B_INHIBIT
) {
1642 for (ap
= itree_next_arrow(bp
, NULL
); ap
;
1643 ap
= itree_next_arrow(bp
, ap
)) {
1644 ASSERT(ap
->arrowp
->head
== bp
);
1645 ASSERT(ap
->arrowp
->tail
!= NULL
);
1646 ASSERT(ap
->arrowp
->tail
->myevent
!= NULL
);
1647 out(flags
|O_NONL
, " ");
1648 itree_pevent_brief(flags
, ap
->arrowp
->tail
->myevent
);
1654 for (ap
= itree_next_arrow(bp
, NULL
); ap
;
1655 ap
= itree_next_arrow(bp
, ap
)) {
1656 ASSERT(ap
->arrowp
->tail
== bp
);
1657 ASSERT(ap
->arrowp
->head
!= NULL
);
1658 ASSERT(ap
->arrowp
->head
->myevent
!= NULL
);
1660 out(flags
|O_NONL
, " ");
1661 itree_pevent_brief(flags
, ap
->arrowp
->head
->myevent
);
1663 out(flags
|O_NONL
, " ");
1664 ptree_timeval(flags
, &ap
->arrowp
->mindelay
);
1665 out(flags
|O_NONL
, ",");
1666 ptree_timeval(flags
, &ap
->arrowp
->maxdelay
);
1668 /* Display anything from the propogation node? */
1669 out(O_VERB3
|O_NONL
, " <%s:%d>",
1670 ap
->arrowp
->pnode
->file
, ap
->arrowp
->pnode
->line
);
1672 if (itree_next_constraint(ap
->arrowp
, NULL
))
1673 out(flags
|O_NONL
, " {");
1675 for (cp
= itree_next_constraint(ap
->arrowp
, NULL
); cp
;
1676 cp
= itree_next_constraint(ap
->arrowp
, cp
)) {
1677 ptree(flags
, cp
->cnode
, 1, 0);
1678 if (itree_next_constraint(ap
->arrowp
, cp
))
1679 out(flags
|O_NONL
, ", ");
1682 if (itree_next_constraint(ap
->arrowp
, NULL
))
1683 out(flags
|O_NONL
, "}");
1689 itree_ptree(int flags
, struct lut
*itp
)
1691 lut_walk(itp
, (lut_cb
)itree_pevent
, (void *)(intptr_t)flags
);
1696 itree_destructor(void *left
, void *right
, void *arg
)
1698 struct event
*ep
= (struct event
*)right
;
1699 struct bubble
*nextbub
, *bub
;
1701 /* Free the properties */
1703 lut_free(ep
->props
, instances_destructor
, NULL
);
1705 /* Free the payload properties */
1706 if (ep
->payloadprops
)
1707 lut_free(ep
->payloadprops
, payloadprops_destructor
, NULL
);
1709 /* Free the serd properties */
1711 lut_free(ep
->serdprops
, serdprops_destructor
, NULL
);
1713 /* Free my bubbles */
1714 for (bub
= ep
->bubbles
; bub
!= NULL
; ) {
1715 nextbub
= bub
->next
;
1717 * Free arrows if they are FROM me. Free arrowlists on
1718 * other types of bubbles (but not the attached arrows,
1719 * which will be freed when we free the originating
1722 if (bub
->t
== B_FROM
)
1723 itree_free_arrowlists(bub
, 1);
1725 itree_free_arrowlists(bub
, 0);
1726 itree_free_bubble(bub
);
1730 nvlist_free(ep
->nvp
);
1731 alloc_xfree(ep
, sizeof (*ep
));
1736 itree_pruner(void *left
, void *right
, void *arg
)
1738 struct event
*ep
= (struct event
*)right
;
1739 struct bubble
*nextbub
, *bub
;
1741 if (ep
->keep_in_tree
)
1744 /* Free the properties */
1745 lut_free(ep
->props
, instances_destructor
, NULL
);
1747 /* Free the payload properties */
1748 lut_free(ep
->payloadprops
, payloadprops_destructor
, NULL
);
1750 /* Free the serd properties */
1751 lut_free(ep
->serdprops
, serdprops_destructor
, NULL
);
1753 /* Free my bubbles */
1754 for (bub
= ep
->bubbles
; bub
!= NULL
; ) {
1755 nextbub
= bub
->next
;
1756 itree_prune_arrowlists(bub
);
1757 itree_free_bubble(bub
);
1761 nvlist_free(ep
->nvp
);
1763 ep
->payloadprops
= NULL
;
1764 ep
->serdprops
= NULL
;
1770 itree_free_bubble(struct bubble
*freeme
)
1772 alloc_xfree(freeme
, sizeof (*freeme
));
1775 static struct bubble
*
1776 itree_add_bubble(struct event
*eventp
, enum bubbletype btype
, int nork
, int gen
)
1778 struct bubble
*prev
= NULL
;
1779 struct bubble
*curr
;
1780 struct bubble
*newb
;
1782 /* Use existing bubbles as appropriate when possible */
1783 for (curr
= eventp
->bubbles
;
1785 prev
= curr
, curr
= curr
->next
) {
1786 if (btype
== B_TO
&& curr
->t
== B_TO
) {
1787 /* see if an existing "to" bubble works for us */
1788 if (gen
== curr
->gen
)
1789 return (curr
); /* matched gen number */
1790 else if (nork
== 1 && curr
->nork
== 1) {
1792 return (curr
); /* coalesce K==1 bubbles */
1794 } else if (btype
== B_FROM
&& curr
->t
== B_FROM
) {
1795 /* see if an existing "from" bubble works for us */
1796 if ((nork
== N_IS_ALL
&& curr
->nork
== N_IS_ALL
) ||
1797 (nork
== 0 && curr
->nork
== 0))
1802 newb
= alloc_xmalloc(sizeof (struct bubble
));
1805 newb
->myevent
= eventp
;
1809 newb
->arrows
= NULL
;
1812 eventp
->bubbles
= newb
;
1820 itree_next_bubble(struct event
*eventp
, struct bubble
*last
)
1822 struct bubble
*next
;
1828 next
= eventp
->bubbles
;
1830 if (next
== NULL
|| next
->arrows
!= NULL
)
1833 /* bubble was empty, skip it */
1839 add_arrow(struct bubble
*bp
, struct arrow
*ap
)
1841 struct arrowlist
*prev
= NULL
;
1842 struct arrowlist
*curr
;
1843 struct arrowlist
*newal
;
1845 newal
= alloc_xmalloc(sizeof (struct arrowlist
));
1846 bzero(newal
, sizeof (struct arrowlist
));
1849 curr
= itree_next_arrow(bp
, NULL
);
1850 while (curr
!= NULL
) {
1852 curr
= itree_next_arrow(bp
, curr
);
1861 static struct arrow
*
1862 itree_add_arrow(struct node
*apnode
, struct node
*fromevent
,
1863 struct node
*toevent
, struct lut
*ex
)
1867 newa
= alloc_xmalloc(sizeof (struct arrow
));
1868 bzero(newa
, sizeof (struct arrow
));
1869 newa
->pnode
= apnode
;
1870 newa
->constraints
= NULL
;
1873 * Set default delays, then try to re-set them from
1874 * any within() constraints.
1876 newa
->mindelay
= newa
->maxdelay
= 0ULL;
1877 if (itree_set_arrow_traits(newa
, fromevent
, toevent
, ex
) == 0) {
1878 alloc_xfree(newa
, sizeof (struct arrow
));
1885 /* returns false if traits show that arrow should not be added after all */
1887 itree_set_arrow_traits(struct arrow
*ap
, struct node
*fromev
,
1888 struct node
*toev
, struct lut
*ex
)
1890 struct node
*events
[] = { NULL
, NULL
, NULL
};
1891 struct node
*newc
= NULL
;
1893 ASSERTeq(fromev
->t
, T_EVENT
, ptree_nodetype2str
);
1894 ASSERTeq(toev
->t
, T_EVENT
, ptree_nodetype2str
);
1897 * search for the within values first on the declaration of
1898 * the destination event, and then on the prop. this allows
1899 * one to specify a "default" within by putting it on the
1900 * declaration, but then allow overriding on the prop statement.
1902 arrow_add_within(ap
, toev
->u
.event
.declp
->u
.stmt
.np
->u
.event
.eexprlist
);
1903 arrow_add_within(ap
, toev
->u
.event
.eexprlist
);
1906 * handle any global constraints inherited from the
1907 * "fromev" event's declaration
1909 ASSERT(fromev
->u
.event
.declp
!= NULL
);
1910 ASSERT(fromev
->u
.event
.declp
->u
.stmt
.np
!= NULL
);
1913 /* XXX not quite ready to evaluate constraints from decls yet */
1914 if (fromev
->u
.event
.declp
->u
.stmt
.np
->u
.event
.eexprlist
)
1915 (void) itree_add_constraint(ap
,
1916 fromev
->u
.event
.declp
->u
.stmt
.np
->u
.event
.eexprlist
);
1919 /* handle constraints on the from event in the prop statement */
1922 if (eval_potential(fromev
->u
.event
.eexprlist
, ex
, events
, &newc
,
1924 return (0); /* constraint disallows arrow */
1927 * handle any global constraints inherited from the
1928 * "toev" event's declaration
1930 ASSERT(toev
->u
.event
.declp
!= NULL
);
1931 ASSERT(toev
->u
.event
.declp
->u
.stmt
.np
!= NULL
);
1934 /* XXX not quite ready to evaluate constraints from decls yet */
1935 if (toev
->u
.event
.declp
->u
.stmt
.np
->u
.event
.eexprlist
)
1936 (void) itree_add_constraint(ap
,
1937 toev
->u
.event
.declp
->u
.stmt
.np
->u
.event
.eexprlist
);
1940 /* handle constraints on the to event in the prop statement */
1943 if (eval_potential(toev
->u
.event
.eexprlist
, ex
, events
, &newc
,
1944 Ninfo
.croot
) == 0) {
1947 return (0); /* constraint disallows arrow */
1950 /* if we came up with any deferred constraints, add them to arrow */
1952 out(O_ALTFP
|O_VERB3
, "(deferred constraints)");
1953 (void) itree_add_constraint(ap
, iexpr(newc
));
1956 return (1); /* constraints allow arrow */
1960 * Set within() constraint. If the constraint were set multiple times,
1961 * the last one would "win".
1964 arrow_add_within(struct arrow
*ap
, struct node
*xpr
)
1966 struct node
*arglist
;
1968 /* end of expressions list */
1974 arrow_add_within(ap
, xpr
->u
.expr
.left
);
1975 arrow_add_within(ap
, xpr
->u
.expr
.right
);
1978 if (xpr
->u
.func
.s
!= L_within
)
1980 arglist
= xpr
->u
.func
.arglist
;
1981 switch (arglist
->t
) {
1984 ap
->maxdelay
= arglist
->u
.ull
;
1987 ASSERT(arglist
->u
.name
.s
== L_infinity
);
1989 ap
->maxdelay
= TIMEVAL_EVENTUALLY
;
1992 ASSERT(arglist
->u
.expr
.left
->t
== T_TIMEVAL
);
1993 ap
->mindelay
= arglist
->u
.expr
.left
->u
.ull
;
1994 switch (arglist
->u
.expr
.right
->t
) {
1996 ap
->maxdelay
= arglist
->u
.ull
;
1999 ASSERT(arglist
->u
.expr
.right
->u
.name
.s
==
2001 ap
->maxdelay
= TIMEVAL_EVENTUALLY
;
2004 out(O_DIE
, "within: unexpected 2nd arg type");
2008 out(O_DIE
, "within: unexpected 1st arg type");
2017 itree_free_arrowlists(struct bubble
*bubp
, int arrows_too
)
2019 struct arrowlist
*al
, *nal
;
2022 while (al
!= NULL
) {
2025 itree_free_constraints(al
->arrowp
);
2026 alloc_xfree(al
->arrowp
, sizeof (struct arrow
));
2028 alloc_xfree(al
, sizeof (*al
));
2034 itree_delete_arrow(struct bubble
*bubp
, struct arrow
*arrow
)
2036 struct arrowlist
*al
, *oal
;
2039 if (al
->arrowp
== arrow
) {
2040 bubp
->arrows
= al
->next
;
2041 alloc_xfree(al
, sizeof (*al
));
2044 while (al
!= NULL
) {
2048 if (al
->arrowp
== arrow
) {
2049 oal
->next
= al
->next
;
2050 alloc_xfree(al
, sizeof (*al
));
2057 itree_prune_arrowlists(struct bubble
*bubp
)
2059 struct arrowlist
*al
, *nal
;
2062 while (al
!= NULL
) {
2064 if (bubp
->t
== B_FROM
)
2065 itree_delete_arrow(al
->arrowp
->head
, al
->arrowp
);
2067 itree_delete_arrow(al
->arrowp
->tail
, al
->arrowp
);
2068 itree_free_constraints(al
->arrowp
);
2069 alloc_xfree(al
->arrowp
, sizeof (struct arrow
));
2070 alloc_xfree(al
, sizeof (*al
));
2076 itree_next_arrow(struct bubble
*bubble
, struct arrowlist
*last
)
2078 struct arrowlist
*next
;
2083 next
= bubble
->arrows
;
2087 static struct constraintlist
*
2088 itree_add_constraint(struct arrow
*arrowp
, struct node
*c
)
2090 struct constraintlist
*prev
= NULL
;
2091 struct constraintlist
*curr
;
2092 struct constraintlist
*newc
;
2094 for (curr
= arrowp
->constraints
;
2096 prev
= curr
, curr
= curr
->next
)
2099 newc
= alloc_xmalloc(sizeof (struct constraintlist
));
2104 arrowp
->constraints
= newc
;
2111 struct constraintlist
*
2112 itree_next_constraint(struct arrow
*arrowp
, struct constraintlist
*last
)
2114 struct constraintlist
*next
;
2119 next
= arrowp
->constraints
;
2124 itree_free_constraints(struct arrow
*ap
)
2126 struct constraintlist
*cl
, *ncl
;
2128 cl
= ap
->constraints
;
2129 while (cl
!= NULL
) {
2131 ASSERT(cl
->cnode
!= NULL
);
2132 if (!iexpr_cached(cl
->cnode
))
2133 tree_free(cl
->cnode
);
2135 iexpr_free(cl
->cnode
);
2136 alloc_xfree(cl
, sizeof (*cl
));
2142 itree_bubbletype2str(enum bubbletype t
)
2144 static char buf
[100];
2147 case B_FROM
: return L_from
;
2148 case B_TO
: return L_to
;
2149 case B_INHIBIT
: return L_inhibit
;
2151 (void) sprintf(buf
, "[unexpected bubbletype: %d]", t
);
2157 * itree_fini -- clean up any half-built itrees
2162 if (Ninfo
.lut
!= NULL
) {
2163 itree_free(Ninfo
.lut
);
2167 lut_free(Ninfo
.ex
, iterinfo_destructor
, NULL
);