3 * If you belong to the group where do you belong only in the case you belong
4 * in that group, do you in fact belong to that group or don't?
5 * I've decided it is safer to decide that you DON'T belong to such group.
7 * expr_eval_notify_expr_remove():
8 * If someone was interested in what am I like but she is no longer
9 * interested in what am I like, because she already knows what is she like,
10 * then she should tell it me, as although I still may not know what am I
11 * like then in the case she was the last who wanted to know what am I like,
12 * I should tell everyone who I didn't know what they are like and I wanted
13 * to know what they are like that I no longer want to know what they are
14 * like, because it is no longer needed to know what am I like about myself.
16 * membership_eval_immediate():
17 * It is important to not only know, what do you want to know, but it is also
18 * important to know what do you now know but you still didn't utilize it.
37 /* Whether to do sanity checks */
38 #define SCAN_PARANOIA 1
40 /* report even no-op scan up-to-date checks */
41 #define REPORT_CHECK_SCAN_VERBOSE 0
44 static void check_request_scan_membership TAC_ARGS((struct membership *membership, int flush));
45 static void check_eval_scan_membership TAC_ARGS((struct membership *membership, int flush));
46 static void check_eval_scan_entity TAC_ARGS((ENTITY *entity, int flush));
47 static void check_request_scan_expr TAC_ARGS((struct expr *expr, int flush));
48 static void check_eval_scan_expr TAC_ARGS((struct expr *expr, int flush));
51 static unsigned request_scan_seq = 0;
52 static unsigned value_scan_seq = 0;
53 static unsigned eval_scan_seq = 0;
54 int request_scan_user_known;
55 static struct tac_list eval_kicked_entity_list;
56 static struct tac_list eval_destroy_entity_list;
57 static struct tac_list eval_notified_expr_list;
58 static struct tac_list request_virtual_membership_list;
61 /* 'P[FA]_*' object printing section:
64 static const char *eval_result_to_string TAC_ARGS((int valid, enum eval_result er));
67 eval_result_to_string(valid, er)
75 case ER_TRUE: return ("ER_TRUE" );
76 case ER_FALSE: return ("ER_FALSE" );
77 case ER_UNKNOWN: return ("ER_UNKNOWN" );
78 default: return ("*** INVALID ***");
83 static const char *value_scan_func_result_to_string TAC_ARGS((enum value_scan_func_result vsfr));
86 value_scan_func_result_to_string(vsfr)
87 enum value_scan_func_result vsfr;
90 case VSFR_CONTINUE: return ("VSFR_CONTINUE");
91 case VSFR_FOUND: return ("VSFR_FOUND" );
92 case VSFR_STOP: return ("VSFR_STOP" );
93 default: return ("*** INVALID ***");
98 /* These macros are VERY big overhead but it's primary negative effect
99 * is the size of executable. I've considered it as not much interesting,
100 * CPU overhead is hit only when DEBUG_CFGEVAL_FLAG (also not interesting).
104 #define PA_VSFR(vsfr) (value_scan_func_result_to_string((vsfr)))
106 #define PF_RESULT "%s"
107 #define PA_RESULT(result) (eval_result_to_string(1 /* valid */, (result)))
109 #define PF_ERESULT_struct PF_RESULT
110 #define PA_ERESULT_struct(entity, field) \
111 (!(entity) ? "*NULL*(=ER_TRUE)" : \
112 (eval_result_to_string((entity)->request_scan.seq == request_scan_seq, (entity)->request_scan.field)))
113 #define PA_ERESULT_struct_NULL "*NULL*"
115 #define PF_ERESULT_EXPR PF_ERESULT_struct
116 #define PA_ERESULT_EXPR(expr) PA_ERESULT_struct((expr), result)
117 #define PF_ERESULT_ENTITY PF_ERESULT_struct
118 #define PA_ERESULT_ENTITY(entity) PA_ERESULT_struct((entity), belongs)
119 #define PF_ERESULT_MEMBERSHIP PF_ERESULT_struct
120 #define PA_ERESULT_MEMBERSHIP(membership) (!(membership) ? PA_ERESULT_struct_NULL : PA_ERESULT_EXPR((membership)->when))
122 #define PF_EXPR_ "expr@%d{%s " PF_MEMBERSHIP "}"
123 #define PA_EXPR_(expr) (!(expr) ? 0 : (expr)->line), \
124 (!(expr) ? "*NULL*" : "of"), \
125 PA_MEMBERSHIP((!(expr) ? NULL : (expr)->membership))
127 #define PF_MEMBERSHIP_ "membership{child=" PF_ENTITY ",parent=" PF_ENTITY "}"
128 #define PA_MEMBERSHIP_(membership) PA_ENTITY((!(membership) ? NULL : MEMBERSHIP_TO_CHILD_ENTITY( (membership)))), \
129 PA_ENTITY((!(membership) ? NULL : MEMBERSHIP_TO_PARENT_ENTITY((membership))))
131 #define PF_ENTITY_ "{%s@%d \"%s\"}"
132 #define PA_ENTITY_(entity) (!(entity) ? "*NULL* entity" : entity_type_to_string((entity)->type)), \
133 (!(entity) ? 0 : (entity)->line), \
134 (!(entity) ? "*NULL*" : (entity)->name)
136 #define PF_EXPR PF_EXPR_ "=" PF_ERESULT_EXPR
137 #define PA_EXPR(expr) PA_EXPR_(expr), PA_ERESULT_EXPR(expr)
138 #define PF_MEMBERSHIP PF_MEMBERSHIP_ "=" PF_ERESULT_MEMBERSHIP
139 #define PA_MEMBERSHIP(membership) PA_MEMBERSHIP_(membership), PA_ERESULT_MEMBERSHIP(membership)
140 #define PF_ENTITY PF_ENTITY_ "=" PF_ERESULT_ENTITY
141 #define PA_ENTITY(entity) PA_ENTITY_(entity), PA_ERESULT_ENTITY(entity)
144 /* '{unlink,free}_*()' section:
147 void unlink_expr TAC_ARGS((struct expr *expr));
149 /* never depend on "->parent" as it may not yet been filled! */
155 return; /* prevent possible DEBUG_CLEAN_FLAG report */
157 if (debug & DEBUG_CLEAN_FLAG) {
158 if (expr->membership)
159 report(LOG_DEBUG, "unlink_expr: (of membership): " PF_EXPR,
162 report(LOG_DEBUG, "unlink_expr: (standalone)");
167 /* We need to at least unlink "eval_scan->u.entity.notify_expr_node": */
168 check_request_scan_expr(expr, 1); /* invalidate */
169 check_eval_scan_expr(expr, 1); /* invalidate */
171 switch (expr->type) {
174 unlink_expr(expr->u.not.child);
179 unlink_expr(expr->u.and_or.child_first);
188 report(LOG_ERR, "Illegal node type %d for unlink_expr", expr->type);
196 void free_expr TAC_ARGS((struct expr *expr));
198 /* given 'expr' memory WILL be freed! */
199 /* never depend on "->parent" as it may not yet been filled! */
204 struct expr *expr_next;
207 return; /* prevent possible DEBUG_CLEAN_FLAG report */
209 if (debug & DEBUG_CLEAN_FLAG)
210 report(LOG_DEBUG, "free_expr: (may be unlinked)");
213 expr_next = expr->next;
214 switch (expr->type) {
217 free_expr(expr->u.not.child);
222 free_expr(expr->u.and_or.child_first);
228 if (expr->u.entity.name)
229 free((/* de-const */ char *)expr->u.entity.name);
230 /* "expr->u.entity.entity" will be freed from elsewhere */
234 report(LOG_ERR, "Illegal node type %d for free_expr", expr->type);
243 static void unlink_membership TAC_ARGS((struct membership *membership));
246 unlink_membership(membership)
247 struct membership *membership;
249 ENTITY *parent_entity;
251 if (debug & DEBUG_CFGEVAL_FLAG)
252 report(LOG_DEBUG, "unlink_membership: " PF_MEMBERSHIP,
253 PA_MEMBERSHIP(membership));
255 parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
257 /* 'unlink_expr()' may want a lot of existing (linked) resources */
258 unlink_expr(membership->when);
260 check_request_scan_membership(membership, 1); /* invalidate */
261 check_eval_scan_membership(membership, 1); /* invalidate */
264 if (!parent_entity->to_child_membership_num) {
265 report(LOG_ERR, "INTERNAL: to_child_membership_num-- == 0 in unlink_membership");
266 parent_entity->to_child_membership_num++;
269 parent_entity->to_child_membership_num--;
271 tac_list_node_remove(&membership->parent_node);
272 tac_list_node_remove(&membership-> child_node);
275 /* given 'membership' memory WILL be freed! */
277 static void free_membership TAC_ARGS((struct membership *membership));
280 free_membership(membership)
281 struct membership *membership;
283 if (debug & DEBUG_CLEAN_FLAG)
284 report(LOG_DEBUG, "free_membership: (may be unlinked)");
286 free_expr(membership->when);
290 /* we are not allowed to free memory here, we are only 'scan_' additional 'free' */
292 void scan_free_entity TAC_ARGS((ENTITY *entity));
295 scan_free_entity(entity)
298 struct tac_list_node *parent_membership_node, *next_parent_membership_node;
299 struct membership *parent_membership;
300 struct tac_list_node *child_membership_node, *next_child_membership_node;
301 struct membership *child_membership;
303 if (debug & DEBUG_CLEAN_FLAG)
304 report(LOG_DEBUG, "scan_free_entity: " PF_ENTITY,
307 /* Be careful to keep '->next' ptr before we destroy the structure! */
310 parent_membership_node = tac_list_first_node(&entity->to_child_membership_list);
311 parent_membership_node;
312 parent_membership_node = next_parent_membership_node
314 parent_membership = PARENT_NODE_TO_MEMBERSHIP(parent_membership_node);
315 next_parent_membership_node = tac_list_node_next(parent_membership_node);
316 unlink_membership(parent_membership);
317 free_membership(parent_membership);
320 child_membership_node = tac_list_first_node(&entity->to_parent_membership_list);
321 child_membership_node;
322 child_membership_node = next_child_membership_node
324 child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
325 next_child_membership_node = tac_list_node_next(child_membership_node);
326 unlink_membership(child_membership);
327 free_membership(child_membership);
331 struct expr *new_expr TAC_ARGS((int type));
339 expr = (struct expr *) tac_malloc(sizeof(struct expr));
342 switch (expr->type) {
345 expr->u.not.child = NULL;
350 expr->u.and_or.child_first = NULL;
356 expr->u.entity.entity = NULL;
360 report(LOG_ERR, "Illegal node type %d for new_expr", expr->type);
361 return (expr); /* it would be probably lethal to return NULL */
366 static int expr_sink_internal TAC_ARGS((struct expr *expr, struct membership *membership, struct expr *parent));
369 expr_sink_internal(expr, membership, parent)
371 struct membership *membership;
374 for (;expr; expr=expr->next) {
375 expr->membership = membership;
376 expr->parent = parent;
377 expr->request_scan.seq = request_scan_seq-1;
378 expr-> eval_scan.seq = eval_scan_seq-1;
379 switch (expr->type) {
382 expr_sink_internal(expr->u.not.child, membership, expr /* parent */);
387 expr_sink_internal(expr->u.and_or.child_first, membership, expr /* parent */);
393 tac_list_node_init(&expr->eval_scan.u.entity.notify_expr_node);
394 expr->u.entity.entity = entity_lookup(expr->type, expr->u.entity.name);
395 if (!expr->u.entity.entity) {
396 report(LOG_ERR, "referenced entity %s %s not found on line %d",
397 entity_type_to_string(expr->type), expr->u.entity.name, expr->line);
400 free((char *) expr->u.entity.name);
401 expr->u.entity.name = NULL;
405 report(LOG_ERR, "Illegal node type %d for expr_sink", expr->type);
412 static int expr_sink TAC_ARGS((struct expr *expr, struct membership *membership));
415 expr_sink(expr, membership)
417 struct membership *membership;
419 return (expr_sink_internal(expr, membership, NULL /* parent */));
422 static struct expr *expr_sink_register_head = NULL;
424 void expr_sink_register TAC_ARGS((struct expr *expr));
427 expr_sink_register(expr)
433 expr->parent = expr_sink_register_head;
434 expr_sink_register_head = expr;
437 int expr_sink_commit TAC_ARGS((void));
444 while ((expr = expr_sink_register_head)) {
445 expr_sink_register_head = expr->parent;
446 /* 'expr->parent' not defined for 'expr_sink()' */
448 if (expr_sink(expr, NULL /* membership */))
449 return (1); /* failure */
451 return (0); /* success */
454 struct expr *dupl_expr TAC_ARGS((const struct expr *in));
458 const struct expr *in;
460 struct expr *expr_root = NULL;
461 struct expr **succ_exprp = &expr_root;
464 for (;in; in=in->next) {
465 expr = (struct expr *) tac_malloc(sizeof(struct expr));
466 expr->line = in->line;
468 expr->type = in->type;
472 if (in->u.not.child && in->u.not.child->type==S_not) {
474 expr = dupl_expr(in->u.not.child->u.not.child);
476 expr->u.not.child = dupl_expr(in->u.not.child);
481 if (!in->u.and_or.child_first) {
484 } else if (!in->u.and_or.child_first->next) {
486 expr = dupl_expr(in->u.and_or.child_first);
488 expr->u.and_or.child_first = dupl_expr(in->u.and_or.child_first);
494 if (in->u.entity.name)
495 expr->u.entity.name = tac_strdup(in->u.entity.name);
497 expr->u.entity.name = NULL;
498 expr->u.entity.entity = in->u.entity.entity;
502 report(LOG_ERR, "Illegal node type %d for dupl_expr", in->type);
503 free_expr(expr_root);
508 succ_exprp = &expr->next;
514 /* 'check_*_scan_*()' section:
517 static void check_request_scan_expr TAC_ARGS((struct expr *expr, int flush));
520 check_request_scan_expr(expr, flush)
524 #if REPORT_CHECK_SCAN_VERBOSE
525 if (debug & DEBUG_CFGEVAL_FLAG)
526 report(LOG_DEBUG, "check_request_scan_expr: " PF_EXPR " (" PF_ERESULT_EXPR ")",
527 PA_EXPR(expr), PA_ERESULT_EXPR(expr));
530 if (!flush && expr->request_scan.seq == request_scan_seq)
531 return; /* up to date */
533 expr->request_scan.result = ER_UNKNOWN;
534 expr->request_scan.loop_reported = 0;
535 expr->request_scan.seq = request_scan_seq;
537 if (debug & DEBUG_CFGEVAL_FLAG)
538 report(LOG_DEBUG, "check_request_scan_expr: done: " PF_EXPR,
542 static void check_eval_scan_expr TAC_ARGS((struct expr *expr, int flush));
545 check_eval_scan_expr(expr, flush)
549 #if REPORT_CHECK_SCAN_VERBOSE
550 if (debug & DEBUG_CFGEVAL_FLAG)
551 report(LOG_DEBUG, "check_eval_scan_expr: " PF_EXPR,
555 if (!flush && expr->eval_scan.seq == eval_scan_seq)
556 return; /* up to date */
557 check_request_scan_expr(expr, 0);
559 switch (expr->type) {
565 if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node) == &eval_notified_expr_list) {
566 report(LOG_ERR, "INTERNAL: expr still connected to eval_notified_expr_list in check_eval_scan_expr");
567 } else if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node)) {
568 ENTITY *notifying_entity = EXPR_ENTITY_TO_NOTIFYING_ENTITY(expr);
570 if (notifying_entity != expr->u.entity.entity)
571 report(LOG_ERR, "INTERNAL: expr->notify_expr_node->list != expr->entity");
572 if (notifying_entity->eval_scan.seq != expr->eval_scan.seq)
573 report(LOG_ERR, "INTERNAL: entity seq != expr node seq");
574 tac_list_node_remove(&expr->eval_scan.u.entity.notify_expr_node);
576 #else /* SCAN_PARANOIA */
577 tac_list_node_init(&expr->eval_scan.u.entity.notify_expr_node);
578 #endif /* SCAN_PARANOIA */
582 expr->eval_scan.seq = eval_scan_seq; /* used above, keep as LAST! */
584 if (debug & DEBUG_CFGEVAL_FLAG)
585 report(LOG_DEBUG, "check_eval_scan_expr: done: " PF_EXPR,
589 static void check_request_scan_membership TAC_ARGS((struct membership *membership, int flush));
592 check_request_scan_membership(membership, flush)
593 struct membership *membership;
596 #if REPORT_CHECK_SCAN_VERBOSE
597 if (debug & DEBUG_CFGEVAL_FLAG)
598 report(LOG_DEBUG, "check_request_scan_membership: " PF_MEMBERSHIP " (" PF_ERESULT_MEMBERSHIP ")",
599 PA_MEMBERSHIP(membership), PA_ERESULT_MEMBERSHIP(membership));
602 if (!flush && membership->request_scan.seq == request_scan_seq)
603 return; /* up to date */
607 struct tac_list *virtual_list = tac_list_node_get_list(&membership->request_scan.virtual_membership_node);
609 if (virtual_list && virtual_list != &request_virtual_membership_list)
610 report(LOG_ERR, "Illegal list in membership->virtual_membership_node.list");
612 tac_list_node_remove(&membership->request_scan.virtual_membership_node);
614 #else /* SCAN_PARANOIA */
615 tac_list_node_init(&membership->request_scan.virtual_membership_node);
616 #endif /* SCAN_PARANOIA */
618 membership->request_scan.seq = request_scan_seq; /* used above, keep as LAST! */
620 if (debug & DEBUG_CFGEVAL_FLAG)
621 report(LOG_DEBUG, "check_request_scan_membership: done: " PF_MEMBERSHIP,
622 PA_MEMBERSHIP(membership));
625 /* we are cross-checking (membership<->parent entity)! */
627 static void check_eval_scan_membership TAC_ARGS((struct membership *membership, int flush));
630 check_eval_scan_membership(membership, flush)
631 struct membership *membership;
634 #if REPORT_CHECK_SCAN_VERBOSE
635 if (debug & DEBUG_CFGEVAL_FLAG)
636 report(LOG_DEBUG, "check_eval_scan_membership: " PF_MEMBERSHIP,
637 PA_MEMBERSHIP(membership));
640 if (!flush && membership->eval_scan.seq == eval_scan_seq)
641 return; /* up to date */
642 check_request_scan_membership(membership, 0);
644 membership->eval_scan.unsolved = 1;
645 membership->eval_scan.seq = eval_scan_seq;
647 if (debug & DEBUG_CFGEVAL_FLAG)
648 report(LOG_DEBUG, "check_eval_scan_membership: done: " PF_MEMBERSHIP,
649 PA_MEMBERSHIP(membership));
652 static void check_request_scan_entity TAC_ARGS((ENTITY *entity, int flush));
655 check_request_scan_entity(entity, flush)
659 #if REPORT_CHECK_SCAN_VERBOSE
660 if (debug & DEBUG_CFGEVAL_FLAG)
661 report(LOG_DEBUG, "check_request_scan_entity: " PF_ENTITY " (" PF_ERESULT_ENTITY ")",
662 PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
665 if (!flush && entity->request_scan.seq == request_scan_seq)
668 entity->request_scan.belongs = ER_UNKNOWN;
669 entity->request_scan.seq = request_scan_seq;
671 if (debug & DEBUG_CFGEVAL_FLAG)
672 report(LOG_DEBUG, "check_request_scan_entity: done: " PF_ENTITY,
676 static void check_value_scan_entity TAC_ARGS((ENTITY *entity, int flush));
679 check_value_scan_entity(entity, flush)
683 #if REPORT_CHECK_SCAN_VERBOSE
684 if (debug & DEBUG_CFGEVAL_FLAG)
685 report(LOG_DEBUG, "check_value_scan_entity: " PF_ENTITY,
689 if (!flush && entity->value_scan.seq == value_scan_seq)
691 check_request_scan_entity(entity, 0);
693 entity->value_scan.seen = 0;
694 entity->value_scan.from = NULL;
695 entity->value_scan.seq = value_scan_seq;
697 if (debug & DEBUG_CFGEVAL_FLAG)
698 report(LOG_DEBUG, "check_value_scan_entity: done: " PF_ENTITY,
702 static void check_eval_scan_entity TAC_ARGS((ENTITY *entity, int flush));
705 check_eval_scan_entity(entity, flush)
709 struct tac_list_node *child_membership_parent_node;
711 #if REPORT_CHECK_SCAN_VERBOSE
712 if (debug & DEBUG_CFGEVAL_FLAG)
713 report(LOG_DEBUG, "check_eval_scan_entity: " PF_ENTITY,
717 if (!flush && entity->eval_scan.seq == eval_scan_seq)
718 return; /* up to date */
719 check_value_scan_entity(entity, 0);
721 entity->eval_scan.unsolved_to_child_membership_num = entity->to_child_membership_num;
723 if ((child_membership_parent_node = tac_list_first_node(&entity->to_child_membership_list))) {
724 struct membership *child_membership = PARENT_NODE_TO_MEMBERSHIP(child_membership_parent_node);
726 entity->eval_scan.unsolved_to_child_membership_first = child_membership;
728 entity->eval_scan.unsolved_to_child_membership_first = NULL;
732 struct tac_list_node *notify_expr_node;
734 while ((notify_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
735 struct expr *notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(notify_expr_node);
737 if (notify_expr->u.entity.entity != entity)
738 report(LOG_ERR, "INTERNAL: notify_expr->entity != entity");
739 if (notify_expr->eval_scan.seq != entity->eval_scan.seq)
740 report(LOG_ERR, "INTERNAL: notify_expr seq != entity seq");
741 tac_list_node_remove(notify_expr_node);
744 if (tac_list_node_get_list(&entity->eval_scan.pending_entity_node))
745 tac_list_node_remove(&entity->eval_scan.pending_entity_node);
747 #else /* SCAN_PARANOIA */
748 tac_list_init(&entity->eval_scan.notify_expr_list);
749 tac_list_node_init(&entity->eval_scan.pending_entity_node);
750 #endif /* SCAN_PARANOIA */
752 entity->eval_scan.seq = eval_scan_seq; /* used above, keep as LAST! */
754 if (debug & DEBUG_CFGEVAL_FLAG)
755 report(LOG_DEBUG, "check_eval_scan_entity: done: " PF_ENTITY,
760 /* invalidation managing section (for '*_scan_begin()'):
763 /* this will happen once upon 'unsigned' overflow, ehm */
765 #define INVALIDATE_SEQ_PTR(object,ptr) \
766 (G_STRUCT_MEMBER(unsigned, ptr, invalidate_scan_##object##_table[what]) = (unsigned) -1)
767 #define INVALIDATE_SEQ(object) \
768 (INVALIDATE_SEQ_PTR(object,object))
770 static const long invalidate_scan_expr_table[IS_MAX]={
771 G_STRUCT_OFFSET(struct expr, request_scan.seq),
773 G_STRUCT_OFFSET(struct expr, eval_scan.seq)};
775 static void invalidate_scan_expr TAC_ARGS((struct expr *expr,enum invalidate_scan what));
778 invalidate_scan_expr(expr_single, what)
779 struct expr *expr_single;
780 enum invalidate_scan what;
782 struct expr *expr_parent, *expr_child;
785 report(LOG_ERR, "INTERNAL: NULL input expressions not support by invalidate_scan_expr");
788 if (expr_single->parent) {
789 report(LOG_ERR, "INTERNAL: non-root expressions not supported by invalidate_scan_expr");
793 /* TOP->DOWN scanner: */
796 INVALIDATE_SEQ_PTR(expr,expr_single);
797 expr_parent = expr_single;
799 switch (expr_parent->type) {
802 expr_child = expr_parent->u.not.child;
807 expr_child = expr_parent->u.and_or.child_first;
813 expr_child = NULL; /* no child exists */
817 report(LOG_ERR, "Illegal child node type %d for invalidate_scan_expr", expr_parent->type);
820 } while ((expr_single = expr_child));
821 /* expr_child==NULL, we have only expr_parent: */
823 expr_child = expr_parent;
825 /* we have only expr_child: */
826 /* BOTTOM->UP scanner */
828 if ((expr_single = expr_child->next))
830 expr_parent = expr_child->parent;
831 } while ((expr_child = expr_parent));
834 static const long invalidate_scan_membership_table[IS_MAX]={
835 G_STRUCT_OFFSET(struct membership, request_scan.seq),
837 G_STRUCT_OFFSET(struct membership, eval_scan.seq)};
839 static void invalidate_scan_membership TAC_ARGS((struct membership *membership,enum invalidate_scan what));
842 invalidate_scan_membership(membership, what)
843 struct membership *membership;
844 enum invalidate_scan what;
846 INVALIDATE_SEQ(membership);
848 if (membership->when)
849 invalidate_scan_expr(membership->when, what);
852 static const long invalidate_scan_entity_table[IS_MAX]={
853 G_STRUCT_OFFSET(ENTITY, request_scan.seq),
854 G_STRUCT_OFFSET(ENTITY, value_scan.seq),
855 G_STRUCT_OFFSET(ENTITY, eval_scan.seq)};
857 static void invalidate_scan_entity TAC_ARGS((ENTITY *entity,enum invalidate_scan what));
860 invalidate_scan_entity(entity, what)
862 enum invalidate_scan what;
864 struct tac_list_node *child_membership_node;
865 struct membership *child_membership;
867 INVALIDATE_SEQ(entity);
869 if (what==IS_VALUE) /* optimalization */
873 child_membership_node = tac_list_first_node(&entity->to_child_membership_list);
874 child_membership_node;
875 child_membership_node = tac_list_node_next(&child_membership->parent_node)
877 child_membership = PARENT_NODE_TO_MEMBERSHIP(child_membership_node);
878 invalidate_scan_membership(child_membership, what);
882 void scan_invalidate_entities_hashtable TAC_ARGS((void **hashtable, enum invalidate_scan what));
885 scan_invalidate_entities_hashtable(hashtable, what)
887 enum invalidate_scan what;
892 for (i = 0; i < HASH_TAB_SIZE; i++)
893 for (entity = (ENTITY *) hashtable[i]; entity; entity = entity->hash)
894 invalidate_scan_entity(entity, what);
897 /* '*_scan_begin()' section:
900 void request_scan_begin TAC_ARGS((void));
906 static int inited = 0;
907 #endif /* SCAN_PARANOIA */
909 if (debug & DEBUG_CFGEVAL_FLAG)
910 report(LOG_DEBUG, "request_scan_begin:");
912 request_scan_user_known = 0;
914 if (!++request_scan_seq)
915 scan_invalidate_entities(IS_REQUEST);
919 #endif /* SCAN_PARANOIA */
920 tac_list_init(&request_virtual_membership_list);
924 struct tac_list_node *virtual_membership_node;
926 while ((virtual_membership_node = tac_list_first_node(&request_virtual_membership_list))) {
927 struct membership *virtual_membership = VIRTUAL_MEMBERSHIP_NODE_TO_MEMBERSHIP(virtual_membership_node);
929 if (virtual_membership->request_scan.seq == request_scan_seq)
930 report(LOG_ERR, "INTERNAL: request_virtual_membership_list membership seq == ++request_scan_seq in request_scan_begin");
931 tac_list_node_remove(virtual_membership_node);
932 unlink_membership(virtual_membership);
933 free_membership(virtual_membership);
936 #endif /* SCAN_PARANOIA */
939 static void value_scan_begin TAC_ARGS((ENTITY *entity));
942 value_scan_begin(entity)
945 if (debug & DEBUG_CFGEVAL_FLAG)
946 report(LOG_DEBUG, "value_scan_begin:");
948 if (!++value_scan_seq)
949 scan_invalidate_entities(IS_VALUE);
951 check_value_scan_entity(entity, 0); /* sure as seq invalidated */
952 /* assumed (entity->value_scan.from == NULL) */
957 static void eval_scan_begin_pending_entity_node TAC_ARGS((struct tac_list_node *pending_entity_node));
960 eval_scan_begin_pending_entity_node(pending_entity_node)
961 struct tac_list_node *pending_entity_node;
963 ENTITY *pending_entity = PENDING_ENTITY_NODE_TO_ENTITY(pending_entity_node);
965 if (pending_entity->eval_scan.seq == eval_scan_seq)
966 report(LOG_ERR, "INTERNAL: eval_{pending}_entity_list entity seq == ++eval_scan_seq in eval_scan_begin");
968 tac_list_node_remove(pending_entity_node);
971 #endif /* SCAN_PARANOIA */
973 static void eval_scan_begin TAC_ARGS((void));
979 static int inited = 0;
980 #endif /* SCAN_PARANOIA */
982 if (debug & DEBUG_CFGEVAL_FLAG)
983 report(LOG_DEBUG, "eval_scan_begin:");
985 if (!++eval_scan_seq)
986 scan_invalidate_entities(IS_EVAL);
990 #endif /* SCAN_PARANOIA */
991 tac_list_init(&eval_kicked_entity_list);
992 tac_list_init(&eval_destroy_entity_list);
993 tac_list_init(&eval_notified_expr_list);
997 struct tac_list_node *pending_entity_node;
998 struct tac_list_node *notify_expr_node;
1000 while ((pending_entity_node = tac_list_first_node(&eval_kicked_entity_list)))
1001 eval_scan_begin_pending_entity_node(pending_entity_node);
1002 while ((pending_entity_node = tac_list_first_node(&eval_destroy_entity_list)))
1003 eval_scan_begin_pending_entity_node(pending_entity_node);
1005 while ((notify_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
1006 struct expr *notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(notify_expr_node);
1008 if (notify_expr->eval_scan.seq == eval_scan_seq)
1009 report(LOG_ERR, "INTERNAL: eval_notified_expr_list expr seq == ++eval_scan_seq in eval_scan_begin");
1011 tac_list_node_remove(notify_expr_node);
1014 #endif /* SCAN_PARANOIA */
1017 /* 'priority=0' => addtail - used for WANTED entities
1018 * 'priority=1' => addhead - used for SOLVED entities
1019 * It may be better to do insert it AFTER all currently solved
1020 * entities but may be not but who cares...
1023 static void register_kicked_entity TAC_ARGS((ENTITY *entity, int priority));
1025 static void register_kicked_entity(entity, priority)
1029 struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
1031 check_eval_scan_entity(entity, 0);
1033 if (tac_list_node_get_list(pending_entity_node) == &eval_destroy_entity_list) {
1034 tac_list_node_remove (pending_entity_node);
1035 if (debug & DEBUG_CFGEVAL_FLAG)
1036 report(LOG_DEBUG, "register_kicked_entity: REMOVED " PF_ENTITY " from eval_DESTROY_entity_list",
1039 if (tac_list_node_get_list(pending_entity_node) == NULL) {
1041 tac_list_addhead(&eval_kicked_entity_list, pending_entity_node);
1043 tac_list_addtail(&eval_kicked_entity_list, pending_entity_node);
1044 if (debug & DEBUG_CFGEVAL_FLAG)
1045 report(LOG_DEBUG, "register_kicked_entity: REGISTERED " PF_ENTITY " to eval_KICKED_entity_list (priority=%s)",
1046 PA_ENTITY(entity), (priority ? "YES" : "NO"));
1048 #ifdef SCAN_PARANOIA
1049 if ((tac_list_node_get_list(pending_entity_node) != &eval_kicked_entity_list)) {
1050 report(LOG_ERR, "Illegal list in entity->pending_entity_node.list");
1056 /* check_eval_scan_*() is assumed both for "expr" and for "entity" ! */
1058 static void expr_eval_notify_expr TAC_ARGS((struct expr *expr));
1061 expr_eval_notify_expr(expr)
1064 ENTITY *entity = expr->u.entity.entity;
1066 if (debug & DEBUG_CFGEVAL_FLAG)
1067 report(LOG_DEBUG, "expr_eval_notify_expr: REGISTERED notify " PF_EXPR " when " PF_ENTITY " is known",
1068 PA_EXPR(expr), PA_ENTITY(entity));
1070 if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
1073 tac_list_addtail(&entity->eval_scan.notify_expr_list,
1074 &expr->eval_scan.u.entity.notify_expr_node);
1076 register_kicked_entity(entity, 0 /* priority */);
1079 /* check_eval_scan_*() is assumed for "expr" ! */
1081 static void expr_eval_notify_expr_remove_internal TAC_ARGS((struct expr *expr));
1084 expr_eval_notify_expr_remove_internal(expr)
1087 if (debug & DEBUG_CFGEVAL_FLAG)
1088 report(LOG_DEBUG, "expr_eval_notify_expr_remove_internal: no longer interested in " PF_EXPR,
1093 if (expr->eval_scan.seq != eval_scan_seq)
1095 if (expr->request_scan.result != ER_UNKNOWN)
1098 switch (expr->type) {
1101 expr_eval_notify_expr_remove_internal(expr->u.not.child);
1108 for (child=expr->u.and_or.child_first; child; child=child->next)
1109 expr_eval_notify_expr_remove_internal(child);
1115 ENTITY *entity = expr->u.entity.entity;
1116 struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
1118 if (!tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
1121 tac_list_node_remove(&expr->eval_scan.u.entity.notify_expr_node);
1122 if (tac_list_first_node(&entity->eval_scan.notify_expr_list))
1124 /* no one is further interested in "entity" */
1126 if ((tac_list_node_get_list(pending_entity_node) == &eval_kicked_entity_list)) {
1127 tac_list_node_remove (pending_entity_node);
1128 if (debug & DEBUG_CFGEVAL_FLAG)
1129 report(LOG_DEBUG, "expr_eval_notify_expr: REMOVED " PF_ENTITY " from eval_KICKED_entity_list",
1132 if (tac_list_node_get_list(pending_entity_node) == NULL) {
1133 tac_list_addtail(&eval_destroy_entity_list, pending_entity_node);
1134 if (debug & DEBUG_CFGEVAL_FLAG)
1135 report(LOG_DEBUG, "expr_eval_notify_expr: REGISTERED " PF_ENTITY " to eval_DESTROY_entity_list",
1138 #ifdef SCAN_PARANOIA
1139 if (tac_list_node_get_list(pending_entity_node) != &eval_destroy_entity_list) {
1140 report(LOG_ERR, "Illegal list in entity->pending_entity_node.list");
1148 report(LOG_ERR, "Illegal node type %d for expr_eval_notify_expr_remove", expr->type);
1153 static void expr_eval_notify_expr_flush_destroy_entity_list TAC_ARGS((void));
1155 static void expr_eval_notify_expr_flush_destroy_entity_list()
1157 struct tac_list_node *destroy_entity_node;
1159 while ((destroy_entity_node = tac_list_first_node(&eval_destroy_entity_list))) {
1160 ENTITY *destroy_entity = PENDING_ENTITY_NODE_TO_ENTITY(destroy_entity_node);
1161 struct tac_list_node *destroy_notify_expr_node;
1163 if (debug & DEBUG_CFGEVAL_FLAG)
1164 report(LOG_DEBUG, "expr_eval_notify_expr_flush_destroy_entity_list: PROCESSING " PF_ENTITY " from eval_DESTROY_entity_list",
1165 PA_ENTITY(destroy_entity));
1167 while ((destroy_notify_expr_node = tac_list_first_node(&destroy_entity->eval_scan.notify_expr_list))) {
1168 struct expr *destroy_notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(destroy_notify_expr_node);
1170 expr_eval_notify_expr_remove_internal(destroy_notify_expr);
1175 static void expr_eval_notify_expr_remove TAC_ARGS((struct expr *expr));
1178 expr_eval_notify_expr_remove(expr)
1181 if (debug & DEBUG_CFGEVAL_FLAG)
1182 report(LOG_DEBUG, "expr_eval_notify_expr_remove: no longer interested in " PF_EXPR,
1185 expr_eval_notify_expr_remove_internal(expr);
1186 expr_eval_notify_expr_flush_destroy_entity_list();
1189 /* It would be very nice to try to optimize the expression before evaluation.
1191 We are not interested in some CPU time complexity of the expression.
1192 But we would be very happy to discard any user/host/group membership
1193 dependencies (our 'variables'). Unfortunately such optimization is
1194 NP problem (classification by courtesy of Daniel Kral) so it is considered
1195 too expensive for us.
1197 TODO in future: Full NP optimization for small number of variables and/or
1198 heuristic optimizations for complex expressions.
1201 static enum eval_result expr_eval_immediate TAC_ARGS((struct expr *expr_single));
1203 static enum eval_result
1204 expr_eval_immediate(expr_single)
1205 struct expr *expr_single;
1207 struct expr *expr_child, *expr_parent;
1208 enum eval_result result_child, result_parent = 0 /* GCC paranoia */;
1210 if (debug & DEBUG_CFGEVAL_FLAG)
1211 report(LOG_DEBUG, "expr_eval_immediate: " PF_EXPR,
1212 PA_EXPR(expr_single));
1217 /* TOP->DOWN scanner: */
1220 enum eval_result result_single;
1222 if (debug & DEBUG_CFGEVAL_FLAG)
1223 report(LOG_DEBUG, "expr_eval_immediate: top_down start: " PF_EXPR,
1224 PA_EXPR(expr_single));
1226 check_eval_scan_expr(expr_single, 0);
1227 result_single = expr_single->request_scan.result;
1228 if (result_single != ER_UNKNOWN)
1230 switch (expr_single->type) {
1233 expr_single = expr_single->u.not.child;
1238 expr_single = expr_single->u.and_or.child_first;
1244 ENTITY *entity = expr_single->u.entity.entity;
1246 check_eval_scan_entity(entity, 0);
1248 if (entity->request_scan.belongs == ER_UNKNOWN)
1249 expr_eval_notify_expr(expr_single);
1251 result_single = entity->request_scan.belongs;
1255 report(LOG_ERR, "Illegal child node type %d for expr_eval", expr_single->type);
1256 return (ER_UNKNOWN);
1259 expr_single->request_scan.result = result_single;
1263 /* BOTTOM->UP scanner: */
1265 if (debug & DEBUG_CFGEVAL_FLAG)
1266 report(LOG_DEBUG, "expr_eval_immediate: bottom_up start: " PF_EXPR,
1267 PA_EXPR(expr_single));
1269 expr_parent = expr_single->parent;
1272 if (expr_parent->eval_scan.seq != eval_scan_seq) {
1273 report(LOG_ERR, "INTERNAL: Parent expr node eval_scan NOT up-to-date");
1274 return (ER_UNKNOWN);
1276 if (expr_parent->request_scan.seq != request_scan_seq) {
1277 report(LOG_ERR, "INTERNAL: Parent expr node request_scan NOT up-to-date");
1278 return (ER_UNKNOWN);
1280 if (expr_parent->request_scan.result != ER_UNKNOWN) {
1281 report(LOG_WARNING, "INTERNAL-WARNING: Parent expr node already known, wasteful eval occured");
1282 return (ER_UNKNOWN);
1285 expr_child = expr_single;
1286 result_child = expr_child->request_scan.result;
1288 if (debug & DEBUG_CFGEVAL_FLAG)
1289 report(LOG_DEBUG, "expr_eval_immediate: bottom_up switch: child=" PF_EXPR ",parent=" PF_EXPR,
1290 PA_EXPR(expr_child), PA_EXPR(expr_parent));
1292 switch (expr_parent->type) {
1295 switch (result_child) {
1296 case ER_UNKNOWN: result_parent = ER_UNKNOWN; break;
1297 case ER_FALSE: result_parent = ER_TRUE; break;
1298 case ER_TRUE: result_parent = ER_FALSE; break;
1304 enum eval_result veto = (expr_parent->type==S_and ? ER_FALSE : ER_TRUE );
1305 enum eval_result consent = (expr_parent->type==S_and ? ER_TRUE : ER_FALSE);
1307 if (result_child == veto)
1308 result_parent = veto;
1309 else if (result_child == ER_UNKNOWN || result_child == consent) {
1310 if (expr_child->next) {
1311 expr_single = expr_child->next;
1312 if (debug & DEBUG_CFGEVAL_FLAG)
1313 report(LOG_DEBUG, "expr_eval_immediate: bottom_up and_or: traversed to and_or next: " PF_EXPR,
1314 PA_EXPR(expr_single));
1318 if (debug & DEBUG_CFGEVAL_FLAG)
1319 report(LOG_DEBUG, "expr_eval_immediate: bottom_up and_or: full scan: " PF_EXPR,
1320 PA_EXPR(expr_single));
1322 result_parent = consent;
1323 for (expr_child = expr_parent->u.and_or.child_first; expr_child; expr_child = expr_child->next)
1325 check_eval_scan_expr(expr_child, 0); /* shouldn't be needed */
1326 if (expr_child->request_scan.result == ER_UNKNOWN)
1327 result_parent = ER_UNKNOWN; /* assumed (result_parent != veto) */
1328 else if (expr_child->request_scan.result == veto) {
1329 result_parent = veto;
1338 report(LOG_ERR, "Illegal parent node type %d for expr_eval", expr_parent->type);
1339 return (ER_UNKNOWN);
1342 if (debug & DEBUG_CFGEVAL_FLAG)
1343 report(LOG_DEBUG, "expr_eval_immediate: bottom_up end: child=" PF_EXPR ",parent=" PF_EXPR,
1344 PA_EXPR(expr_child), PA_EXPR(expr_parent));
1346 if (result_parent != ER_UNKNOWN) {
1347 expr_parent->request_scan.result = result_parent;
1348 /* we no longer need any notifications from entities to solve sub-expression */
1349 expr_eval_notify_expr_remove(expr_parent);
1352 expr_single = expr_parent;
1354 /* The whole expression has been scanned to its root, we have "expr_single" */
1356 if (debug & DEBUG_CFGEVAL_FLAG)
1357 report(LOG_DEBUG, "expr_eval_immediate: done: " PF_EXPR,
1358 PA_EXPR(expr_single));
1360 return (expr_single->request_scan.result);
1363 static void membership_solved TAC_ARGS((struct membership *membership));
1366 membership_solved(membership)
1367 struct membership *membership;
1369 ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1371 check_request_scan_entity(parent_entity, 0);
1373 #ifdef SCAN_PARANOIA
1374 if (!membership->eval_scan.unsolved) {
1375 report(LOG_ERR, "INTERNAL: membership already solved in membership_solved");
1380 membership->eval_scan.unsolved = 0;
1382 #ifdef SCAN_PARANOIA
1383 if (!parent_entity->eval_scan.unsolved_to_child_membership_num) {
1384 report(LOG_ERR, "INTERNAL: unsolved_to_child_membership_num-- == 0 in membership_solved");
1385 parent_entity->eval_scan.unsolved_to_child_membership_num++;
1388 parent_entity->eval_scan.unsolved_to_child_membership_num--;
1390 if (!parent_entity->eval_scan.unsolved_to_child_membership_num
1391 && parent_entity->request_scan.belongs == ER_UNKNOWN) {
1392 parent_entity->request_scan.belongs = ER_FALSE;
1393 register_kicked_entity(parent_entity, 1 /* priority */);
1397 static void membership_parent_solve TAC_ARGS((struct membership *membership, enum eval_result how));
1400 membership_parent_solve(membership, how)
1401 struct membership *membership;
1402 enum eval_result how;
1404 enum eval_result negative = (how == ER_TRUE ? ER_FALSE : ER_TRUE);
1405 ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1407 check_request_scan_entity(parent_entity, 0);
1409 if (parent_entity->request_scan.belongs == negative)
1410 report(LOG_ERR, "INTERNAL: parent " PF_ENTITY "already negative to what says membership " PF_MEMBERSHIP "in membership_eval_immediate",
1411 PA_ENTITY(parent_entity), PA_MEMBERSHIP(membership));
1413 parent_entity->request_scan.belongs = how;
1414 register_kicked_entity(parent_entity, 1 /* priority */);
1416 membership_solved(membership);
1418 if (debug & DEBUG_CFGEVAL_FLAG)
1419 report(LOG_DEBUG, "membership_parent_solve: " PF_MEMBERSHIP " marked parent " PF_ENTITY,
1420 PA_MEMBERSHIP(membership), PA_ENTITY(parent_entity));
1423 static void membership_eval_immediate TAC_ARGS((struct membership *membership));
1426 membership_eval_immediate(membership)
1427 struct membership *membership;
1429 enum eval_result membership_valid;
1430 ENTITY *child_entity, *parent_entity;
1432 if (debug & DEBUG_CFGEVAL_FLAG)
1433 report(LOG_DEBUG, "membership_eval_immediate: " PF_MEMBERSHIP,
1434 PA_MEMBERSHIP(membership));
1436 check_eval_scan_membership(membership, 0);
1438 if (!membership->eval_scan.unsolved)
1440 parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1441 check_request_scan_entity(parent_entity, 0);
1442 if (parent_entity->request_scan.belongs != ER_UNKNOWN) /* why to solve this membership? */
1445 membership_valid = expr_eval_immediate(membership->when);
1447 child_entity = MEMBERSHIP_TO_CHILD_ENTITY( membership);
1448 check_request_scan_entity( child_entity, 0);
1450 #if 0 /* non-valid membership doesn't YET solve the parent! */
1451 if (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE) {
1452 membership_parent_solve(membership, ER_FALSE);
1457 if (child_entity->request_scan.belongs == ER_TRUE && membership_valid == ER_TRUE ) {
1458 membership_parent_solve(membership, ER_TRUE );
1462 if ( child_entity->request_scan.belongs == ER_UNKNOWN)
1463 register_kicked_entity( child_entity, 0 /* priority */);
1464 if (parent_entity->request_scan.belongs == ER_UNKNOWN)
1465 register_kicked_entity(parent_entity, 0 /* priority */);
1467 if (parent_entity->request_scan.belongs != ER_UNKNOWN
1468 || (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE))
1469 membership_solved(membership);
1471 if (debug & DEBUG_CFGEVAL_FLAG)
1472 report(LOG_DEBUG, "membership_eval_immediate: done: " PF_MEMBERSHIP,
1473 PA_MEMBERSHIP(membership));
1476 static void entity_eval_immediate TAC_ARGS((ENTITY *entity));
1479 entity_eval_immediate(entity)
1482 struct tac_list_node *notified_expr_node;
1483 struct tac_list_node *child_membership_node;
1485 if (debug & DEBUG_CFGEVAL_FLAG)
1486 report(LOG_DEBUG, "entity_eval_immediate: " PF_ENTITY,
1489 check_eval_scan_entity(entity, 0);
1491 if (!request_scan_user_known) {
1492 #ifdef SCAN_PARANOIA
1493 if (entity->request_scan.belongs != ER_UNKNOWN)
1494 report(LOG_ERR, "INTERNAL: belonging known while still !request_scan_user_known for " PF_ENTITY " in entity_eval_immediate",
1500 if (entity->request_scan.belongs == ER_UNKNOWN) {
1501 if (entity->eval_scan.unsolved_to_child_membership_first) {
1502 struct membership *order_membership = entity->eval_scan.unsolved_to_child_membership_first;
1503 struct tac_list_node *next_membership_parent_node = tac_list_node_next(&order_membership->parent_node);
1505 membership_eval_immediate(order_membership);
1506 if (next_membership_parent_node)
1507 entity->eval_scan.unsolved_to_child_membership_first = PARENT_NODE_TO_MEMBERSHIP(next_membership_parent_node);
1509 entity->eval_scan.unsolved_to_child_membership_first = NULL;
1511 register_kicked_entity(entity, 0 /* priority */);
1513 if (debug & DEBUG_CFGEVAL_FLAG)
1514 report(LOG_DEBUG, "entity_eval_immediate: finishing as we ordered child membership: " PF_MEMBERSHIP,
1515 PA_MEMBERSHIP(order_membership));
1519 if (!entity->eval_scan.unsolved_to_child_membership_num)
1520 entity->request_scan.belongs = ER_FALSE;
1522 if (debug & DEBUG_CFGEVAL_FLAG)
1523 report(LOG_DEBUG, "entity_eval_immediate: finishing as unsolved child memberships still available and I'm still clueless");
1527 /* belonging is known here */
1529 /* recheck all memberships we may decide */
1531 child_membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1532 child_membership_node;
1533 child_membership_node = tac_list_node_next(child_membership_node)
1535 struct membership *child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
1537 membership_eval_immediate(child_membership);
1540 /* notify all exprs which are interested in us */
1541 while ((notified_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
1542 tac_list_node_remove(notified_expr_node);
1543 tac_list_addtail(&eval_notified_expr_list, notified_expr_node);
1546 if (debug & DEBUG_CFGEVAL_FLAG)
1547 report(LOG_DEBUG, "entity_eval_immediate: done: " PF_ENTITY,
1552 enum eval_result expr_eval TAC_ARGS((struct expr *expr));
1558 if (debug & DEBUG_CFGEVAL_FLAG)
1559 report(LOG_DEBUG, "expr_eval: top level order for " PF_EXPR,
1566 if (expr_eval_immediate(expr) != ER_UNKNOWN)
1567 return (expr->request_scan.result);
1569 /* all 'solved' nodes MUST be removed BEFORE '*_immediate()' has been called,
1570 * otherwise we may have no longer valid node!
1573 struct tac_list_node *notified_expr_node, *kicked_entity_node;
1575 /* check it rather always, checking just on notifications looks too complex.
1577 if (expr->request_scan.result != ER_UNKNOWN) {
1578 if (debug & DEBUG_CFGEVAL_FLAG)
1579 report(LOG_DEBUG, "expr_eval: finishing as ordered " PF_EXPR " got known",
1581 return (expr->request_scan.result);
1584 #if 0 /* not needed as it is now always called after any destroy */
1585 expr_eval_notify_expr_flush_destroy_entity_list(); /* eval_destroy_entity_list */
1586 #endif /* not needed */
1588 if ((notified_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
1589 struct expr *notified_expr = NOTIFY_EXPR_NODE_TO_EXPR(notified_expr_node);
1591 if (debug & DEBUG_CFGEVAL_FLAG)
1592 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_EXPR " from eval_NOTIFIED_expr_list",
1593 PA_EXPR(notified_expr));
1595 tac_list_node_remove(notified_expr_node);
1596 expr_eval_immediate(notified_expr);
1598 if (notified_expr->membership)
1599 membership_eval_immediate(notified_expr->membership);
1601 continue; /* shortcut */
1604 if ((kicked_entity_node = tac_list_first_node(&eval_kicked_entity_list))) {
1605 ENTITY *kicked_entity = PENDING_ENTITY_NODE_TO_ENTITY(kicked_entity_node);
1607 if (debug & DEBUG_CFGEVAL_FLAG)
1608 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_ENTITY " from eval_KICKED_entity_list",
1609 PA_ENTITY(kicked_entity));
1611 tac_list_node_remove(kicked_entity_node);
1612 entity_eval_immediate(kicked_entity);
1613 continue; /* shortcut */
1616 break; /* nothing done yet, all lists are empty! */
1619 if (!expr->request_scan.loop_reported) {
1620 report(LOG_WARNING, "Unable to resolve expression from line %d, some looping occured", expr->line);
1621 expr->request_scan.loop_reported = 1;
1623 return (ER_UNKNOWN);
1627 void eval_force_belong_entity TAC_ARGS((ENTITY *entity));
1629 void eval_force_belong_entity(entity)
1632 if (debug & DEBUG_CFGEVAL_FLAG)
1633 report(LOG_DEBUG, "eval_force_belong_entity: " PF_ENTITY " (before check_scan " PF_ERESULT_ENTITY ")",
1634 PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
1636 check_request_scan_entity(entity, 0);
1638 if (entity->request_scan.belongs == ER_FALSE)
1639 report(LOG_ERR, "Dangerous force of TRUE to FALSE-determined entity in eval_force_belong_entity");
1641 entity->request_scan.belongs = ER_TRUE;
1644 void scan_init_entity TAC_ARGS((ENTITY *entity));
1647 scan_init_entity(entity)
1650 entity->request_scan.seq = request_scan_seq-1; /* invalidate */
1651 entity-> value_scan.seq = value_scan_seq-1; /* invalidate */
1652 entity-> eval_scan.seq = eval_scan_seq-1; /* invalidate */
1653 tac_list_init(&entity->eval_scan.notify_expr_list);
1654 tac_list_node_init(&entity->eval_scan.pending_entity_node);
1657 struct membership *enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child, struct expr *when));
1660 enlist_entity_direct(parent, child, when)
1665 struct membership *membership = (struct membership *) tac_malloc(sizeof(struct membership));
1667 tac_list_node_init(&membership->parent_node);
1668 tac_list_node_init(&membership->child_node);
1669 membership->request_scan.seq = request_scan_seq-1;
1670 tac_list_node_init(&membership->request_scan.virtual_membership_node);
1671 membership->eval_scan.seq = eval_scan_seq-1;
1673 tac_list_addtail(&parent->to_child_membership_list , &membership->parent_node);
1674 parent->to_child_membership_num++;
1675 tac_list_addtail(& child->to_parent_membership_list, &membership-> child_node);
1676 membership->when = when;
1677 if (expr_sink(membership->when, membership)) {
1678 unlink_membership(membership);
1679 free_membership(membership);
1683 if (debug & DEBUG_CFGEVAL_FLAG)
1684 report(LOG_DEBUG, "enlist_entity_direct: done: " PF_MEMBERSHIP,
1685 PA_MEMBERSHIP(membership));
1687 return (membership);
1690 struct membership *virtual_enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child));
1693 virtual_enlist_entity_direct(parent, child)
1697 struct membership *membership;
1699 if (debug & DEBUG_CFGEVAL_FLAG)
1700 report(LOG_DEBUG, "virtual_enlist_entity_direct: the following enlist will be VIRTUAL...");
1702 membership = enlist_entity_direct(parent, child, NULL /* when */);
1706 check_request_scan_membership(membership, 0);
1707 tac_list_addtail(&request_virtual_membership_list, &membership->request_scan.virtual_membership_node);
1709 return (membership);
1712 /* returns given 'entity' or NULL if already visited */
1714 void (*value_scan_forward_seen_hook) TAC_ARGS((struct membership *membership));
1716 static ENTITY *value_scan_forward TAC_ARGS((struct membership *membership));
1719 value_scan_forward(membership)
1720 struct membership *membership;
1722 ENTITY *parent_entity;
1724 if (debug & DEBUG_CFGEVAL_FLAG)
1725 report(LOG_DEBUG, "value_scan_forward: from " PF_MEMBERSHIP " try forward...",
1726 PA_MEMBERSHIP(membership));
1728 parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1730 if (ER_TRUE != expr_eval(membership->when)) {
1731 if (debug & DEBUG_CFGEVAL_FLAG)
1732 report(LOG_DEBUG, "value_scan_forward: forward NOT successful due to failed 'when' evaluation.");
1735 check_value_scan_entity(parent_entity, 0);
1736 if (parent_entity->value_scan.seen) {
1737 if (debug & DEBUG_CFGEVAL_FLAG)
1738 report(LOG_DEBUG, "value_scan_forward: forward NOT successful as the parent " PF_ENTITY " was already seen this value scan.",
1739 PA_ENTITY(parent_entity));
1740 if (value_scan_forward_seen_hook)
1741 (*value_scan_forward_seen_hook)(membership);
1744 parent_entity->value_scan.seen = 1;
1745 parent_entity->value_scan.from = membership;
1747 if (debug & DEBUG_CFGEVAL_FLAG)
1748 report(LOG_DEBUG, "value_scan_forward: forward SUCCESSFUL to parent " PF_ENTITY,
1749 PA_ENTITY(parent_entity));
1750 return (parent_entity);
1753 struct membership *value_scan_backward TAC_ARGS((ENTITY *entity));
1756 value_scan_backward(entity)
1759 if (debug & DEBUG_CFGEVAL_FLAG)
1760 report(LOG_DEBUG, "value_scan_backward: from " PF_ENTITY " went back to " PF_MEMBERSHIP,
1761 PA_ENTITY(entity), PA_MEMBERSHIP(entity->value_scan.from));
1763 #ifdef SCAN_PARANOIA
1764 if (entity->value_scan.seq != value_scan_seq) {
1765 report(LOG_ERR, "entity value_scan NOT up-to-date in value_scan_backward");
1770 return (entity->value_scan.from);
1773 /* Scan the entity graph and return each node found.
1774 'when' conditions for graph connections are respected,
1775 looping is correctly prevented.
1778 enum value_scan_func_result value_scan_entity TAC_ARGS((ENTITY *entity, int recurse, value_scan_func_t func, void *func_data));
1780 enum value_scan_func_result
1781 value_scan_entity(entity, recurse, func, func_data)
1784 value_scan_func_t func;
1787 enum value_scan_func_result vsfr;
1788 struct tac_list_node *membership_node;
1790 if (debug & DEBUG_CFGEVAL_FLAG)
1791 report(LOG_DEBUG, "value_scan_entity: " PF_ENTITY ", recurse=%d",
1792 PA_ENTITY(entity), recurse);
1794 vsfr=(*func)(entity,func_data);
1796 if (debug & DEBUG_CFGEVAL_FLAG)
1797 report(LOG_DEBUG, "value_scan_entity: root func-> " PF_VSFR,
1800 if (vsfr != VSFR_CONTINUE) {
1801 if (debug & DEBUG_CFGEVAL_FLAG)
1802 report(LOG_DEBUG, "value_scan_entity: finishing as root func didn't return VSFR_CONTINUE");
1806 if (debug & DEBUG_CFGEVAL_FLAG)
1807 report(LOG_DEBUG, "value_scan_entity: finishing as recurse not ordered");
1811 value_scan_begin(entity);
1812 membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1813 if (!membership_node) {
1814 if (debug & DEBUG_CFGEVAL_FLAG)
1815 report(LOG_DEBUG, "value_scan_entity: finishing as no parent entities of root");
1816 return (VSFR_CONTINUE); /* no parent entities */
1820 struct membership *membership = CHILD_NODE_TO_MEMBERSHIP(membership_node);
1822 if (debug & DEBUG_CFGEVAL_FLAG)
1823 report(LOG_DEBUG, "value_scan_entity: trace loop start: " PF_MEMBERSHIP,
1824 PA_MEMBERSHIP(membership));
1826 entity = value_scan_forward(membership);
1828 if (debug & DEBUG_CFGEVAL_FLAG)
1829 report(LOG_DEBUG, "value_scan_entity: successful recurse to " PF_ENTITY,
1832 vsfr=(*func)(entity,func_data);
1834 if (debug & DEBUG_CFGEVAL_FLAG)
1835 report(LOG_DEBUG, "value_scan_entity: func(" PF_ENTITY ")-> " PF_VSFR,
1836 PA_ENTITY(entity), PA_VSFR(vsfr));
1838 if (vsfr == VSFR_FOUND) {
1839 if (debug & DEBUG_CFGEVAL_FLAG)
1840 report(LOG_DEBUG, "value_scan_entity: finishing as func returned VSFR_FOUND");
1843 if (vsfr == VSFR_CONTINUE)
1844 membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1846 if (!entity || vsfr == VSFR_STOP) {
1847 ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1849 entity = MEMBERSHIP_TO_CHILD_ENTITY(membership); /* for retreat from the LAST membership */
1851 if (debug & DEBUG_CFGEVAL_FLAG)
1852 report(LOG_DEBUG, "value_scan_entity: unsuccessful recurse to " PF_ENTITY ", tracing back through child " PF_ENTITY,
1853 PA_ENTITY(parent_entity), PA_ENTITY(entity));
1855 membership_node = tac_list_node_next(&membership->child_node);
1858 while (!membership_node) {
1859 membership = value_scan_backward(entity);
1861 if (debug & DEBUG_CFGEVAL_FLAG)
1862 report(LOG_DEBUG, "value_scan_entity: finishing as all nodes were scanned");
1863 return (VSFR_CONTINUE); /* FINISH */
1866 entity = MEMBERSHIP_TO_CHILD_ENTITY(membership); /* for retreat from the LAST membership */
1868 if (debug & DEBUG_CFGEVAL_FLAG)
1869 report(LOG_DEBUG, "value_scan_entity: backward retreat ('next' chase) "
1870 "through " PF_MEMBERSHIP " to child " PF_ENTITY,
1871 PA_MEMBERSHIP(membership), PA_ENTITY(entity));
1873 membership_node = tac_list_node_next(&membership->child_node);