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)) {
1071 #ifdef SCAN_PARANOIA
1072 if (&entity->eval_scan.notify_expr_list
1073 != tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
1074 report(LOG_ERR, "Another " PF_ENTITY " already registered in notify node of " PF_EXPR,
1075 PA_ENTITY(EXPR_ENTITY_TO_NOTIFYING_ENTITY(expr)), PA_EXPR(expr));
1080 tac_list_addtail(&entity->eval_scan.notify_expr_list,
1081 &expr->eval_scan.u.entity.notify_expr_node);
1083 register_kicked_entity(entity, 0 /* priority */);
1086 /* check_eval_scan_*() is assumed for "expr" ! */
1088 static void expr_eval_notify_expr_remove_internal TAC_ARGS((struct expr *expr));
1091 expr_eval_notify_expr_remove_internal(expr)
1094 if (debug & DEBUG_CFGEVAL_FLAG)
1095 report(LOG_DEBUG, "expr_eval_notify_expr_remove_internal: no longer interested in " PF_EXPR,
1100 if (expr->eval_scan.seq != eval_scan_seq)
1102 if (expr->request_scan.result != ER_UNKNOWN)
1105 switch (expr->type) {
1108 expr_eval_notify_expr_remove_internal(expr->u.not.child);
1115 for (child=expr->u.and_or.child_first; child; child=child->next)
1116 expr_eval_notify_expr_remove_internal(child);
1122 ENTITY *entity = expr->u.entity.entity;
1123 struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
1125 if (!tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
1128 tac_list_node_remove(&expr->eval_scan.u.entity.notify_expr_node);
1129 if (tac_list_first_node(&entity->eval_scan.notify_expr_list))
1131 /* no one is further interested in "entity" */
1133 if ((tac_list_node_get_list(pending_entity_node) == &eval_kicked_entity_list)) {
1134 tac_list_node_remove (pending_entity_node);
1135 if (debug & DEBUG_CFGEVAL_FLAG)
1136 report(LOG_DEBUG, "expr_eval_notify_expr: REMOVED " PF_ENTITY " from eval_KICKED_entity_list",
1139 if (tac_list_node_get_list(pending_entity_node) == NULL) {
1140 tac_list_addtail(&eval_destroy_entity_list, pending_entity_node);
1141 if (debug & DEBUG_CFGEVAL_FLAG)
1142 report(LOG_DEBUG, "expr_eval_notify_expr: REGISTERED " PF_ENTITY " to eval_DESTROY_entity_list",
1145 #ifdef SCAN_PARANOIA
1146 if (tac_list_node_get_list(pending_entity_node) != &eval_destroy_entity_list) {
1147 report(LOG_ERR, "Illegal list in entity->pending_entity_node.list");
1155 report(LOG_ERR, "Illegal node type %d for expr_eval_notify_expr_remove", expr->type);
1160 static void expr_eval_notify_expr_flush_destroy_entity_list TAC_ARGS((void));
1162 static void expr_eval_notify_expr_flush_destroy_entity_list()
1164 struct tac_list_node *destroy_entity_node;
1166 while ((destroy_entity_node = tac_list_first_node(&eval_destroy_entity_list))) {
1167 ENTITY *destroy_entity = PENDING_ENTITY_NODE_TO_ENTITY(destroy_entity_node);
1168 struct tac_list_node *destroy_notify_expr_node;
1170 if (debug & DEBUG_CFGEVAL_FLAG)
1171 report(LOG_DEBUG, "expr_eval_notify_expr_flush_destroy_entity_list: PROCESSING " PF_ENTITY " from eval_DESTROY_entity_list",
1172 PA_ENTITY(destroy_entity));
1174 while ((destroy_notify_expr_node = tac_list_first_node(&destroy_entity->eval_scan.notify_expr_list))) {
1175 struct expr *destroy_notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(destroy_notify_expr_node);
1177 expr_eval_notify_expr_remove_internal(destroy_notify_expr);
1182 static void expr_eval_notify_expr_remove TAC_ARGS((struct expr *expr));
1185 expr_eval_notify_expr_remove(expr)
1188 if (debug & DEBUG_CFGEVAL_FLAG)
1189 report(LOG_DEBUG, "expr_eval_notify_expr_remove: no longer interested in " PF_EXPR,
1192 expr_eval_notify_expr_remove_internal(expr);
1193 expr_eval_notify_expr_flush_destroy_entity_list();
1196 /* It would be very nice to try to optimize the expression before evaluation.
1198 We are not interested in some CPU time complexity of the expression.
1199 But we would be very happy to discard any user/host/group membership
1200 dependencies (our 'variables'). Unfortunately such optimization is
1201 NP problem (classification by courtesy of Daniel Kral) so it is considered
1202 too expensive for us.
1204 TODO in future: Full NP optimization for small number of variables and/or
1205 heuristic optimizations for complex expressions.
1208 static enum eval_result expr_eval_immediate TAC_ARGS((struct expr *expr_single));
1210 static enum eval_result
1211 expr_eval_immediate(expr_single)
1212 struct expr *expr_single;
1214 struct expr *expr_child, *expr_parent;
1215 enum eval_result result_child, result_parent = 0 /* GCC paranoia */;
1217 if (debug & DEBUG_CFGEVAL_FLAG)
1218 report(LOG_DEBUG, "expr_eval_immediate: " PF_EXPR,
1219 PA_EXPR(expr_single));
1224 /* TOP->DOWN scanner: */
1227 enum eval_result result_single;
1229 if (debug & DEBUG_CFGEVAL_FLAG)
1230 report(LOG_DEBUG, "expr_eval_immediate: top_down start: " PF_EXPR,
1231 PA_EXPR(expr_single));
1233 check_eval_scan_expr(expr_single, 0);
1234 result_single = expr_single->request_scan.result;
1235 if (result_single != ER_UNKNOWN)
1237 switch (expr_single->type) {
1240 expr_single = expr_single->u.not.child;
1245 expr_single = expr_single->u.and_or.child_first;
1251 ENTITY *entity = expr_single->u.entity.entity;
1253 check_eval_scan_entity(entity, 0);
1255 if (entity->request_scan.belongs == ER_UNKNOWN)
1256 expr_eval_notify_expr(expr_single);
1258 result_single = entity->request_scan.belongs;
1262 report(LOG_ERR, "Illegal child node type %d for expr_eval", expr_single->type);
1263 return (ER_UNKNOWN);
1266 expr_single->request_scan.result = result_single;
1270 /* BOTTOM->UP scanner: */
1272 if (debug & DEBUG_CFGEVAL_FLAG)
1273 report(LOG_DEBUG, "expr_eval_immediate: bottom_up start: " PF_EXPR,
1274 PA_EXPR(expr_single));
1276 expr_parent = expr_single->parent;
1279 if (expr_parent->eval_scan.seq != eval_scan_seq) {
1280 report(LOG_ERR, "INTERNAL: Parent expr node eval_scan NOT up-to-date");
1281 return (ER_UNKNOWN);
1283 if (expr_parent->request_scan.seq != request_scan_seq) {
1284 report(LOG_ERR, "INTERNAL: Parent expr node request_scan NOT up-to-date");
1285 return (ER_UNKNOWN);
1287 if (expr_parent->request_scan.result != ER_UNKNOWN) {
1288 report(LOG_WARNING, "INTERNAL-WARNING: Parent expr node already known, wasteful eval occured");
1289 return (ER_UNKNOWN);
1292 expr_child = expr_single;
1293 result_child = expr_child->request_scan.result;
1295 if (debug & DEBUG_CFGEVAL_FLAG)
1296 report(LOG_DEBUG, "expr_eval_immediate: bottom_up switch: child=" PF_EXPR ",parent=" PF_EXPR,
1297 PA_EXPR(expr_child), PA_EXPR(expr_parent));
1299 switch (expr_parent->type) {
1302 switch (result_child) {
1303 case ER_UNKNOWN: result_parent = ER_UNKNOWN; break;
1304 case ER_FALSE: result_parent = ER_TRUE; break;
1305 case ER_TRUE: result_parent = ER_FALSE; break;
1311 enum eval_result veto = (expr_parent->type==S_and ? ER_FALSE : ER_TRUE );
1312 enum eval_result consent = (expr_parent->type==S_and ? ER_TRUE : ER_FALSE);
1314 if (result_child == veto)
1315 result_parent = veto;
1316 else if (result_child == ER_UNKNOWN || result_child == consent) {
1317 if (expr_child->next) {
1318 expr_single = expr_child->next;
1319 if (debug & DEBUG_CFGEVAL_FLAG)
1320 report(LOG_DEBUG, "expr_eval_immediate: bottom_up and_or: traversed to and_or next: " PF_EXPR,
1321 PA_EXPR(expr_single));
1325 if (debug & DEBUG_CFGEVAL_FLAG)
1326 report(LOG_DEBUG, "expr_eval_immediate: bottom_up and_or: full scan: " PF_EXPR,
1327 PA_EXPR(expr_single));
1329 /* It would be nice to pretend that all 'veto' decisions already made in the child
1330 * had to set our 'result' to the correct value. But 'consent' decisions don't set
1331 * us and the behaviour of auto-set from the child in 'veto' case may get changed
1332 * in the future versions.
1333 * So we rather don't depend on it.
1334 * This overhead doesn't change altgorithmic complexity anyway.
1336 result_parent = consent;
1337 for (expr_child = expr_parent->u.and_or.child_first; expr_child; expr_child = expr_child->next)
1339 check_eval_scan_expr(expr_child, 0); /* shouldn't be needed */
1340 if (expr_child->request_scan.result == ER_UNKNOWN)
1341 result_parent = ER_UNKNOWN; /* assumed (result_parent != veto) */
1342 else if (expr_child->request_scan.result == veto) {
1343 result_parent = veto;
1352 report(LOG_ERR, "Illegal parent node type %d for expr_eval", expr_parent->type);
1353 return (ER_UNKNOWN);
1356 if (debug & DEBUG_CFGEVAL_FLAG)
1357 report(LOG_DEBUG, "expr_eval_immediate: bottom_up end: child=" PF_EXPR ",parent=" PF_EXPR,
1358 PA_EXPR(expr_child), PA_EXPR(expr_parent));
1360 if (result_parent != ER_UNKNOWN) {
1361 expr_parent->request_scan.result = result_parent;
1362 /* we no longer need any notifications from entities to solve sub-expression */
1363 expr_eval_notify_expr_remove(expr_parent);
1366 expr_single = expr_parent;
1368 /* The whole expression has been scanned to its root, we have "expr_single" */
1370 if (debug & DEBUG_CFGEVAL_FLAG)
1371 report(LOG_DEBUG, "expr_eval_immediate: done: " PF_EXPR,
1372 PA_EXPR(expr_single));
1374 return (expr_single->request_scan.result);
1377 static void membership_solved TAC_ARGS((struct membership *membership));
1380 membership_solved(membership)
1381 struct membership *membership;
1383 ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1385 check_request_scan_entity(parent_entity, 0);
1387 #ifdef SCAN_PARANOIA
1388 if (!membership->eval_scan.unsolved) {
1389 report(LOG_ERR, "INTERNAL: membership already solved in membership_solved");
1394 membership->eval_scan.unsolved = 0;
1396 #ifdef SCAN_PARANOIA
1397 if (!parent_entity->eval_scan.unsolved_to_child_membership_num) {
1398 report(LOG_ERR, "INTERNAL: unsolved_to_child_membership_num-- == 0 in membership_solved");
1399 parent_entity->eval_scan.unsolved_to_child_membership_num++;
1402 parent_entity->eval_scan.unsolved_to_child_membership_num--;
1404 if (!parent_entity->eval_scan.unsolved_to_child_membership_num
1405 && parent_entity->request_scan.belongs == ER_UNKNOWN) {
1406 parent_entity->request_scan.belongs = ER_FALSE;
1407 register_kicked_entity(parent_entity, 1 /* priority */);
1411 static void membership_parent_solve TAC_ARGS((struct membership *membership, enum eval_result how));
1414 membership_parent_solve(membership, how)
1415 struct membership *membership;
1416 enum eval_result how;
1418 enum eval_result negative = (how == ER_TRUE ? ER_FALSE : ER_TRUE);
1419 ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1421 check_request_scan_entity(parent_entity, 0);
1423 if (parent_entity->request_scan.belongs == negative)
1424 report(LOG_ERR, "INTERNAL: parent " PF_ENTITY "already negative to what says membership " PF_MEMBERSHIP "in membership_eval_immediate",
1425 PA_ENTITY(parent_entity), PA_MEMBERSHIP(membership));
1427 parent_entity->request_scan.belongs = how;
1428 register_kicked_entity(parent_entity, 1 /* priority */);
1430 membership_solved(membership);
1432 if (debug & DEBUG_CFGEVAL_FLAG)
1433 report(LOG_DEBUG, "membership_parent_solve: " PF_MEMBERSHIP " marked parent " PF_ENTITY,
1434 PA_MEMBERSHIP(membership), PA_ENTITY(parent_entity));
1437 static void membership_eval_immediate TAC_ARGS((struct membership *membership));
1440 membership_eval_immediate(membership)
1441 struct membership *membership;
1443 enum eval_result membership_valid;
1444 ENTITY *child_entity, *parent_entity;
1446 if (debug & DEBUG_CFGEVAL_FLAG)
1447 report(LOG_DEBUG, "membership_eval_immediate: " PF_MEMBERSHIP,
1448 PA_MEMBERSHIP(membership));
1450 check_eval_scan_membership(membership, 0);
1452 if (!membership->eval_scan.unsolved)
1454 parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1455 check_request_scan_entity(parent_entity, 0);
1456 if (parent_entity->request_scan.belongs != ER_UNKNOWN) /* why to solve this membership? */
1459 membership_valid = expr_eval_immediate(membership->when);
1461 child_entity = MEMBERSHIP_TO_CHILD_ENTITY( membership);
1462 check_request_scan_entity( child_entity, 0);
1464 #if 0 /* non-valid membership doesn't YET solve the parent! */
1465 if (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE) {
1466 membership_parent_solve(membership, ER_FALSE);
1471 if (child_entity->request_scan.belongs == ER_TRUE && membership_valid == ER_TRUE ) {
1472 membership_parent_solve(membership, ER_TRUE );
1476 if ( child_entity->request_scan.belongs == ER_UNKNOWN)
1477 register_kicked_entity( child_entity, 0 /* priority */);
1478 if (parent_entity->request_scan.belongs == ER_UNKNOWN)
1479 register_kicked_entity(parent_entity, 0 /* priority */);
1481 if (parent_entity->request_scan.belongs != ER_UNKNOWN
1482 || (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE))
1483 membership_solved(membership);
1485 if (debug & DEBUG_CFGEVAL_FLAG)
1486 report(LOG_DEBUG, "membership_eval_immediate: done: " PF_MEMBERSHIP,
1487 PA_MEMBERSHIP(membership));
1490 static void entity_eval_immediate TAC_ARGS((ENTITY *entity));
1493 entity_eval_immediate(entity)
1496 struct tac_list_node *notified_expr_node;
1497 struct tac_list_node *child_membership_node;
1499 if (debug & DEBUG_CFGEVAL_FLAG)
1500 report(LOG_DEBUG, "entity_eval_immediate: " PF_ENTITY,
1503 check_eval_scan_entity(entity, 0);
1505 if (!request_scan_user_known) {
1506 #ifdef SCAN_PARANOIA
1507 if (entity->request_scan.belongs != ER_UNKNOWN)
1508 report(LOG_ERR, "INTERNAL: belonging known while still !request_scan_user_known for " PF_ENTITY " in entity_eval_immediate",
1514 if (entity->request_scan.belongs == ER_UNKNOWN) {
1515 if (entity->eval_scan.unsolved_to_child_membership_first) {
1516 struct membership *order_membership = entity->eval_scan.unsolved_to_child_membership_first;
1517 struct tac_list_node *next_membership_parent_node = tac_list_node_next(&order_membership->parent_node);
1519 membership_eval_immediate(order_membership);
1520 if (next_membership_parent_node)
1521 entity->eval_scan.unsolved_to_child_membership_first = PARENT_NODE_TO_MEMBERSHIP(next_membership_parent_node);
1523 entity->eval_scan.unsolved_to_child_membership_first = NULL;
1525 register_kicked_entity(entity, 0 /* priority */);
1527 if (debug & DEBUG_CFGEVAL_FLAG)
1528 report(LOG_DEBUG, "entity_eval_immediate: finishing as we ordered child membership: " PF_MEMBERSHIP,
1529 PA_MEMBERSHIP(order_membership));
1533 if (!entity->eval_scan.unsolved_to_child_membership_num)
1534 entity->request_scan.belongs = ER_FALSE;
1536 if (debug & DEBUG_CFGEVAL_FLAG)
1537 report(LOG_DEBUG, "entity_eval_immediate: finishing as unsolved child memberships still available and I'm still clueless");
1541 /* belonging is known here */
1543 /* recheck all memberships we may decide */
1545 child_membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1546 child_membership_node;
1547 child_membership_node = tac_list_node_next(child_membership_node)
1549 struct membership *child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
1551 membership_eval_immediate(child_membership);
1554 /* notify all exprs which are interested in us */
1555 while ((notified_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
1556 tac_list_node_remove(notified_expr_node);
1557 tac_list_addtail(&eval_notified_expr_list, notified_expr_node);
1560 if (debug & DEBUG_CFGEVAL_FLAG)
1561 report(LOG_DEBUG, "entity_eval_immediate: done: " PF_ENTITY,
1566 enum eval_result expr_eval TAC_ARGS((struct expr *expr));
1572 if (debug & DEBUG_CFGEVAL_FLAG)
1573 report(LOG_DEBUG, "expr_eval: top level order for " PF_EXPR,
1580 if (expr_eval_immediate(expr) != ER_UNKNOWN)
1581 return (expr->request_scan.result);
1583 /* all 'solved' nodes MUST be removed BEFORE '*_immediate()' has been called,
1584 * otherwise we may have no longer valid node!
1587 struct tac_list_node *notified_expr_node, *kicked_entity_node;
1589 /* check it rather always, checking just on notifications looks too complex.
1591 if (expr->request_scan.result != ER_UNKNOWN) {
1592 if (debug & DEBUG_CFGEVAL_FLAG)
1593 report(LOG_DEBUG, "expr_eval: finishing as ordered " PF_EXPR " got known",
1595 return (expr->request_scan.result);
1598 #if 0 /* not needed as it is now always called after any destroy */
1599 expr_eval_notify_expr_flush_destroy_entity_list(); /* eval_destroy_entity_list */
1600 #endif /* not needed */
1602 if ((notified_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
1603 struct expr *notified_expr = NOTIFY_EXPR_NODE_TO_EXPR(notified_expr_node);
1605 if (debug & DEBUG_CFGEVAL_FLAG)
1606 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_EXPR " from eval_NOTIFIED_expr_list",
1607 PA_EXPR(notified_expr));
1609 tac_list_node_remove(notified_expr_node);
1610 expr_eval_immediate(notified_expr);
1612 if (notified_expr->membership)
1613 membership_eval_immediate(notified_expr->membership);
1615 continue; /* shortcut */
1618 if ((kicked_entity_node = tac_list_first_node(&eval_kicked_entity_list))) {
1619 ENTITY *kicked_entity = PENDING_ENTITY_NODE_TO_ENTITY(kicked_entity_node);
1621 if (debug & DEBUG_CFGEVAL_FLAG)
1622 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_ENTITY " from eval_KICKED_entity_list",
1623 PA_ENTITY(kicked_entity));
1625 tac_list_node_remove(kicked_entity_node);
1626 entity_eval_immediate(kicked_entity);
1627 continue; /* shortcut */
1630 break; /* nothing done yet, all lists are empty! */
1633 if (!expr->request_scan.loop_reported) {
1634 report(LOG_WARNING, "Unable to resolve expression from line %d, some looping occured", expr->line);
1635 expr->request_scan.loop_reported = 1;
1637 return (ER_UNKNOWN);
1641 void eval_force_belong_entity TAC_ARGS((ENTITY *entity));
1643 void eval_force_belong_entity(entity)
1646 if (debug & DEBUG_CFGEVAL_FLAG)
1647 report(LOG_DEBUG, "eval_force_belong_entity: " PF_ENTITY " (before check_scan " PF_ERESULT_ENTITY ")",
1648 PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
1650 check_request_scan_entity(entity, 0);
1652 if (entity->request_scan.belongs == ER_FALSE)
1653 report(LOG_ERR, "Dangerous force of TRUE to FALSE-determined entity in eval_force_belong_entity");
1655 entity->request_scan.belongs = ER_TRUE;
1658 void scan_init_entity TAC_ARGS((ENTITY *entity));
1661 scan_init_entity(entity)
1664 entity->request_scan.seq = request_scan_seq-1; /* invalidate */
1665 entity-> value_scan.seq = value_scan_seq-1; /* invalidate */
1666 entity-> eval_scan.seq = eval_scan_seq-1; /* invalidate */
1667 tac_list_init(&entity->eval_scan.notify_expr_list);
1668 tac_list_node_init(&entity->eval_scan.pending_entity_node);
1671 struct membership *enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child, struct expr *when));
1674 enlist_entity_direct(parent, child, when)
1679 struct membership *membership = (struct membership *) tac_malloc(sizeof(struct membership));
1681 tac_list_node_init(&membership->parent_node);
1682 tac_list_node_init(&membership->child_node);
1683 membership->request_scan.seq = request_scan_seq-1;
1684 tac_list_node_init(&membership->request_scan.virtual_membership_node);
1685 membership->eval_scan.seq = eval_scan_seq-1;
1687 tac_list_addtail(&parent->to_child_membership_list , &membership->parent_node);
1688 parent->to_child_membership_num++;
1689 tac_list_addtail(& child->to_parent_membership_list, &membership-> child_node);
1690 membership->when = when;
1691 if (expr_sink(membership->when, membership)) {
1692 unlink_membership(membership);
1693 free_membership(membership);
1697 if (debug & DEBUG_CFGEVAL_FLAG)
1698 report(LOG_DEBUG, "enlist_entity_direct: done: " PF_MEMBERSHIP,
1699 PA_MEMBERSHIP(membership));
1701 return (membership);
1704 struct membership *virtual_enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child));
1707 virtual_enlist_entity_direct(parent, child)
1711 struct membership *membership;
1713 if (debug & DEBUG_CFGEVAL_FLAG)
1714 report(LOG_DEBUG, "virtual_enlist_entity_direct: the following enlist will be VIRTUAL...");
1716 membership = enlist_entity_direct(parent, child, NULL /* when */);
1720 check_request_scan_membership(membership, 0);
1721 tac_list_addtail(&request_virtual_membership_list, &membership->request_scan.virtual_membership_node);
1723 return (membership);
1726 /* returns given 'entity' or NULL if already visited */
1728 void (*value_scan_forward_seen_hook) TAC_ARGS((struct membership *membership));
1730 static ENTITY *value_scan_forward TAC_ARGS((struct membership *membership));
1733 value_scan_forward(membership)
1734 struct membership *membership;
1736 ENTITY *parent_entity;
1738 if (debug & DEBUG_CFGEVAL_FLAG)
1739 report(LOG_DEBUG, "value_scan_forward: from " PF_MEMBERSHIP " try forward...",
1740 PA_MEMBERSHIP(membership));
1742 parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1744 if (ER_TRUE != expr_eval(membership->when)) {
1745 if (debug & DEBUG_CFGEVAL_FLAG)
1746 report(LOG_DEBUG, "value_scan_forward: forward NOT successful due to failed 'when' evaluation.");
1749 check_value_scan_entity(parent_entity, 0);
1750 if (parent_entity->value_scan.seen) {
1751 if (debug & DEBUG_CFGEVAL_FLAG)
1752 report(LOG_DEBUG, "value_scan_forward: forward NOT successful as the parent " PF_ENTITY " was already seen this value scan.",
1753 PA_ENTITY(parent_entity));
1754 if (value_scan_forward_seen_hook)
1755 (*value_scan_forward_seen_hook)(membership);
1758 parent_entity->value_scan.seen = 1;
1759 parent_entity->value_scan.from = membership;
1761 if (debug & DEBUG_CFGEVAL_FLAG)
1762 report(LOG_DEBUG, "value_scan_forward: forward SUCCESSFUL to parent " PF_ENTITY,
1763 PA_ENTITY(parent_entity));
1764 return (parent_entity);
1767 struct membership *value_scan_backward TAC_ARGS((ENTITY *entity));
1770 value_scan_backward(entity)
1773 if (debug & DEBUG_CFGEVAL_FLAG)
1774 report(LOG_DEBUG, "value_scan_backward: from " PF_ENTITY " went back to " PF_MEMBERSHIP,
1775 PA_ENTITY(entity), PA_MEMBERSHIP(entity->value_scan.from));
1777 #ifdef SCAN_PARANOIA
1778 if (entity->value_scan.seq != value_scan_seq) {
1779 report(LOG_ERR, "entity value_scan NOT up-to-date in value_scan_backward");
1784 return (entity->value_scan.from);
1787 /* Scan the entity graph and return each node found.
1788 'when' conditions for graph connections are respected,
1789 looping is correctly prevented.
1792 enum value_scan_func_result value_scan_entity TAC_ARGS((ENTITY *entity, int recurse, value_scan_func_t func, void *func_data));
1794 enum value_scan_func_result
1795 value_scan_entity(entity, recurse, func, func_data)
1798 value_scan_func_t func;
1801 enum value_scan_func_result vsfr;
1802 struct tac_list_node *membership_node;
1804 if (debug & DEBUG_CFGEVAL_FLAG)
1805 report(LOG_DEBUG, "value_scan_entity: " PF_ENTITY ", recurse=%d",
1806 PA_ENTITY(entity), recurse);
1808 vsfr=(*func)(entity,func_data);
1810 if (debug & DEBUG_CFGEVAL_FLAG)
1811 report(LOG_DEBUG, "value_scan_entity: root func-> " PF_VSFR,
1814 if (vsfr != VSFR_CONTINUE) {
1815 if (debug & DEBUG_CFGEVAL_FLAG)
1816 report(LOG_DEBUG, "value_scan_entity: finishing as root func didn't return VSFR_CONTINUE");
1820 if (debug & DEBUG_CFGEVAL_FLAG)
1821 report(LOG_DEBUG, "value_scan_entity: finishing as recurse not ordered");
1825 value_scan_begin(entity);
1826 membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1827 if (!membership_node) {
1828 if (debug & DEBUG_CFGEVAL_FLAG)
1829 report(LOG_DEBUG, "value_scan_entity: finishing as no parent entities of root");
1830 return (VSFR_CONTINUE); /* no parent entities */
1834 struct membership *membership = CHILD_NODE_TO_MEMBERSHIP(membership_node);
1836 if (debug & DEBUG_CFGEVAL_FLAG)
1837 report(LOG_DEBUG, "value_scan_entity: trace loop start: " PF_MEMBERSHIP,
1838 PA_MEMBERSHIP(membership));
1840 entity = value_scan_forward(membership);
1842 if (debug & DEBUG_CFGEVAL_FLAG)
1843 report(LOG_DEBUG, "value_scan_entity: successful recurse to " PF_ENTITY,
1846 vsfr=(*func)(entity,func_data);
1848 if (debug & DEBUG_CFGEVAL_FLAG)
1849 report(LOG_DEBUG, "value_scan_entity: func(" PF_ENTITY ")-> " PF_VSFR,
1850 PA_ENTITY(entity), PA_VSFR(vsfr));
1852 if (vsfr == VSFR_FOUND) {
1853 if (debug & DEBUG_CFGEVAL_FLAG)
1854 report(LOG_DEBUG, "value_scan_entity: finishing as func returned VSFR_FOUND");
1857 if (vsfr == VSFR_CONTINUE)
1858 membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1860 if (!entity || vsfr == VSFR_STOP) {
1861 ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1863 entity = MEMBERSHIP_TO_CHILD_ENTITY(membership); /* for retreat from the LAST membership */
1865 if (debug & DEBUG_CFGEVAL_FLAG)
1866 report(LOG_DEBUG, "value_scan_entity: unsuccessful recurse to " PF_ENTITY ", tracing back through child " PF_ENTITY,
1867 PA_ENTITY(parent_entity), PA_ENTITY(entity));
1869 membership_node = tac_list_node_next(&membership->child_node);
1872 while (!membership_node) {
1873 membership = value_scan_backward(entity);
1875 if (debug & DEBUG_CFGEVAL_FLAG)
1876 report(LOG_DEBUG, "value_scan_entity: finishing as all nodes were scanned");
1877 return (VSFR_CONTINUE); /* FINISH */
1880 entity = MEMBERSHIP_TO_CHILD_ENTITY(membership); /* for retreat from the LAST membership */
1882 if (debug & DEBUG_CFGEVAL_FLAG)
1883 report(LOG_DEBUG, "value_scan_entity: backward retreat ('next' chase) "
1884 "through " PF_MEMBERSHIP " to child " PF_ENTITY,
1885 PA_MEMBERSHIP(membership), PA_ENTITY(entity));
1887 membership_node = tac_list_node_next(&membership->child_node);