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 result_parent = consent;
1330 for (expr_child = expr_parent->u.and_or.child_first; expr_child; expr_child = expr_child->next)
1332 check_eval_scan_expr(expr_child, 0); /* shouldn't be needed */
1333 if (expr_child->request_scan.result == ER_UNKNOWN)
1334 result_parent = ER_UNKNOWN; /* assumed (result_parent != veto) */
1335 else if (expr_child->request_scan.result == veto) {
1336 result_parent = veto;
1345 report(LOG_ERR, "Illegal parent node type %d for expr_eval", expr_parent->type);
1346 return (ER_UNKNOWN);
1349 if (debug & DEBUG_CFGEVAL_FLAG)
1350 report(LOG_DEBUG, "expr_eval_immediate: bottom_up end: child=" PF_EXPR ",parent=" PF_EXPR,
1351 PA_EXPR(expr_child), PA_EXPR(expr_parent));
1353 if (result_parent != ER_UNKNOWN) {
1354 expr_parent->request_scan.result = result_parent;
1355 /* we no longer need any notifications from entities to solve sub-expression */
1356 expr_eval_notify_expr_remove(expr_parent);
1359 expr_single = expr_parent;
1361 /* The whole expression has been scanned to its root, we have "expr_single" */
1363 if (debug & DEBUG_CFGEVAL_FLAG)
1364 report(LOG_DEBUG, "expr_eval_immediate: done: " PF_EXPR,
1365 PA_EXPR(expr_single));
1367 return (expr_single->request_scan.result);
1370 static void membership_solved TAC_ARGS((struct membership *membership));
1373 membership_solved(membership)
1374 struct membership *membership;
1376 ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1378 check_request_scan_entity(parent_entity, 0);
1380 #ifdef SCAN_PARANOIA
1381 if (!membership->eval_scan.unsolved) {
1382 report(LOG_ERR, "INTERNAL: membership already solved in membership_solved");
1387 membership->eval_scan.unsolved = 0;
1389 #ifdef SCAN_PARANOIA
1390 if (!parent_entity->eval_scan.unsolved_to_child_membership_num) {
1391 report(LOG_ERR, "INTERNAL: unsolved_to_child_membership_num-- == 0 in membership_solved");
1392 parent_entity->eval_scan.unsolved_to_child_membership_num++;
1395 parent_entity->eval_scan.unsolved_to_child_membership_num--;
1397 if (!parent_entity->eval_scan.unsolved_to_child_membership_num
1398 && parent_entity->request_scan.belongs == ER_UNKNOWN) {
1399 parent_entity->request_scan.belongs = ER_FALSE;
1400 register_kicked_entity(parent_entity, 1 /* priority */);
1404 static void membership_parent_solve TAC_ARGS((struct membership *membership, enum eval_result how));
1407 membership_parent_solve(membership, how)
1408 struct membership *membership;
1409 enum eval_result how;
1411 enum eval_result negative = (how == ER_TRUE ? ER_FALSE : ER_TRUE);
1412 ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1414 check_request_scan_entity(parent_entity, 0);
1416 if (parent_entity->request_scan.belongs == negative)
1417 report(LOG_ERR, "INTERNAL: parent " PF_ENTITY "already negative to what says membership " PF_MEMBERSHIP "in membership_eval_immediate",
1418 PA_ENTITY(parent_entity), PA_MEMBERSHIP(membership));
1420 parent_entity->request_scan.belongs = how;
1421 register_kicked_entity(parent_entity, 1 /* priority */);
1423 membership_solved(membership);
1425 if (debug & DEBUG_CFGEVAL_FLAG)
1426 report(LOG_DEBUG, "membership_parent_solve: " PF_MEMBERSHIP " marked parent " PF_ENTITY,
1427 PA_MEMBERSHIP(membership), PA_ENTITY(parent_entity));
1430 static void membership_eval_immediate TAC_ARGS((struct membership *membership));
1433 membership_eval_immediate(membership)
1434 struct membership *membership;
1436 enum eval_result membership_valid;
1437 ENTITY *child_entity, *parent_entity;
1439 if (debug & DEBUG_CFGEVAL_FLAG)
1440 report(LOG_DEBUG, "membership_eval_immediate: " PF_MEMBERSHIP,
1441 PA_MEMBERSHIP(membership));
1443 check_eval_scan_membership(membership, 0);
1445 if (!membership->eval_scan.unsolved)
1447 parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1448 check_request_scan_entity(parent_entity, 0);
1449 if (parent_entity->request_scan.belongs != ER_UNKNOWN) /* why to solve this membership? */
1452 membership_valid = expr_eval_immediate(membership->when);
1454 child_entity = MEMBERSHIP_TO_CHILD_ENTITY( membership);
1455 check_request_scan_entity( child_entity, 0);
1457 #if 0 /* non-valid membership doesn't YET solve the parent! */
1458 if (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE) {
1459 membership_parent_solve(membership, ER_FALSE);
1464 if (child_entity->request_scan.belongs == ER_TRUE && membership_valid == ER_TRUE ) {
1465 membership_parent_solve(membership, ER_TRUE );
1469 if ( child_entity->request_scan.belongs == ER_UNKNOWN)
1470 register_kicked_entity( child_entity, 0 /* priority */);
1471 if (parent_entity->request_scan.belongs == ER_UNKNOWN)
1472 register_kicked_entity(parent_entity, 0 /* priority */);
1474 if (parent_entity->request_scan.belongs != ER_UNKNOWN
1475 || (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE))
1476 membership_solved(membership);
1478 if (debug & DEBUG_CFGEVAL_FLAG)
1479 report(LOG_DEBUG, "membership_eval_immediate: done: " PF_MEMBERSHIP,
1480 PA_MEMBERSHIP(membership));
1483 static void entity_eval_immediate TAC_ARGS((ENTITY *entity));
1486 entity_eval_immediate(entity)
1489 struct tac_list_node *notified_expr_node;
1490 struct tac_list_node *child_membership_node;
1492 if (debug & DEBUG_CFGEVAL_FLAG)
1493 report(LOG_DEBUG, "entity_eval_immediate: " PF_ENTITY,
1496 check_eval_scan_entity(entity, 0);
1498 if (!request_scan_user_known) {
1499 #ifdef SCAN_PARANOIA
1500 if (entity->request_scan.belongs != ER_UNKNOWN)
1501 report(LOG_ERR, "INTERNAL: belonging known while still !request_scan_user_known for " PF_ENTITY " in entity_eval_immediate",
1507 if (entity->request_scan.belongs == ER_UNKNOWN) {
1508 if (entity->eval_scan.unsolved_to_child_membership_first) {
1509 struct membership *order_membership = entity->eval_scan.unsolved_to_child_membership_first;
1510 struct tac_list_node *next_membership_parent_node = tac_list_node_next(&order_membership->parent_node);
1512 membership_eval_immediate(order_membership);
1513 if (next_membership_parent_node)
1514 entity->eval_scan.unsolved_to_child_membership_first = PARENT_NODE_TO_MEMBERSHIP(next_membership_parent_node);
1516 entity->eval_scan.unsolved_to_child_membership_first = NULL;
1518 register_kicked_entity(entity, 0 /* priority */);
1520 if (debug & DEBUG_CFGEVAL_FLAG)
1521 report(LOG_DEBUG, "entity_eval_immediate: finishing as we ordered child membership: " PF_MEMBERSHIP,
1522 PA_MEMBERSHIP(order_membership));
1526 if (!entity->eval_scan.unsolved_to_child_membership_num)
1527 entity->request_scan.belongs = ER_FALSE;
1529 if (debug & DEBUG_CFGEVAL_FLAG)
1530 report(LOG_DEBUG, "entity_eval_immediate: finishing as unsolved child memberships still available and I'm still clueless");
1534 /* belonging is known here */
1536 /* recheck all memberships we may decide */
1538 child_membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1539 child_membership_node;
1540 child_membership_node = tac_list_node_next(child_membership_node)
1542 struct membership *child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
1544 membership_eval_immediate(child_membership);
1547 /* notify all exprs which are interested in us */
1548 while ((notified_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
1549 tac_list_node_remove(notified_expr_node);
1550 tac_list_addtail(&eval_notified_expr_list, notified_expr_node);
1553 if (debug & DEBUG_CFGEVAL_FLAG)
1554 report(LOG_DEBUG, "entity_eval_immediate: done: " PF_ENTITY,
1559 enum eval_result expr_eval TAC_ARGS((struct expr *expr));
1565 if (debug & DEBUG_CFGEVAL_FLAG)
1566 report(LOG_DEBUG, "expr_eval: top level order for " PF_EXPR,
1573 if (expr_eval_immediate(expr) != ER_UNKNOWN)
1574 return (expr->request_scan.result);
1576 /* all 'solved' nodes MUST be removed BEFORE '*_immediate()' has been called,
1577 * otherwise we may have no longer valid node!
1580 struct tac_list_node *notified_expr_node, *kicked_entity_node;
1582 /* check it rather always, checking just on notifications looks too complex.
1584 if (expr->request_scan.result != ER_UNKNOWN) {
1585 if (debug & DEBUG_CFGEVAL_FLAG)
1586 report(LOG_DEBUG, "expr_eval: finishing as ordered " PF_EXPR " got known",
1588 return (expr->request_scan.result);
1591 #if 0 /* not needed as it is now always called after any destroy */
1592 expr_eval_notify_expr_flush_destroy_entity_list(); /* eval_destroy_entity_list */
1593 #endif /* not needed */
1595 if ((notified_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
1596 struct expr *notified_expr = NOTIFY_EXPR_NODE_TO_EXPR(notified_expr_node);
1598 if (debug & DEBUG_CFGEVAL_FLAG)
1599 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_EXPR " from eval_NOTIFIED_expr_list",
1600 PA_EXPR(notified_expr));
1602 tac_list_node_remove(notified_expr_node);
1603 expr_eval_immediate(notified_expr);
1605 if (notified_expr->membership)
1606 membership_eval_immediate(notified_expr->membership);
1608 continue; /* shortcut */
1611 if ((kicked_entity_node = tac_list_first_node(&eval_kicked_entity_list))) {
1612 ENTITY *kicked_entity = PENDING_ENTITY_NODE_TO_ENTITY(kicked_entity_node);
1614 if (debug & DEBUG_CFGEVAL_FLAG)
1615 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_ENTITY " from eval_KICKED_entity_list",
1616 PA_ENTITY(kicked_entity));
1618 tac_list_node_remove(kicked_entity_node);
1619 entity_eval_immediate(kicked_entity);
1620 continue; /* shortcut */
1623 break; /* nothing done yet, all lists are empty! */
1626 if (!expr->request_scan.loop_reported) {
1627 report(LOG_WARNING, "Unable to resolve expression from line %d, some looping occured", expr->line);
1628 expr->request_scan.loop_reported = 1;
1630 return (ER_UNKNOWN);
1634 void eval_force_belong_entity TAC_ARGS((ENTITY *entity));
1636 void eval_force_belong_entity(entity)
1639 if (debug & DEBUG_CFGEVAL_FLAG)
1640 report(LOG_DEBUG, "eval_force_belong_entity: " PF_ENTITY " (before check_scan " PF_ERESULT_ENTITY ")",
1641 PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
1643 check_request_scan_entity(entity, 0);
1645 if (entity->request_scan.belongs == ER_FALSE)
1646 report(LOG_ERR, "Dangerous force of TRUE to FALSE-determined entity in eval_force_belong_entity");
1648 entity->request_scan.belongs = ER_TRUE;
1651 void scan_init_entity TAC_ARGS((ENTITY *entity));
1654 scan_init_entity(entity)
1657 entity->request_scan.seq = request_scan_seq-1; /* invalidate */
1658 entity-> value_scan.seq = value_scan_seq-1; /* invalidate */
1659 entity-> eval_scan.seq = eval_scan_seq-1; /* invalidate */
1660 tac_list_init(&entity->eval_scan.notify_expr_list);
1661 tac_list_node_init(&entity->eval_scan.pending_entity_node);
1664 struct membership *enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child, struct expr *when));
1667 enlist_entity_direct(parent, child, when)
1672 struct membership *membership = (struct membership *) tac_malloc(sizeof(struct membership));
1674 tac_list_node_init(&membership->parent_node);
1675 tac_list_node_init(&membership->child_node);
1676 membership->request_scan.seq = request_scan_seq-1;
1677 tac_list_node_init(&membership->request_scan.virtual_membership_node);
1678 membership->eval_scan.seq = eval_scan_seq-1;
1680 tac_list_addtail(&parent->to_child_membership_list , &membership->parent_node);
1681 parent->to_child_membership_num++;
1682 tac_list_addtail(& child->to_parent_membership_list, &membership-> child_node);
1683 membership->when = when;
1684 if (expr_sink(membership->when, membership)) {
1685 unlink_membership(membership);
1686 free_membership(membership);
1690 if (debug & DEBUG_CFGEVAL_FLAG)
1691 report(LOG_DEBUG, "enlist_entity_direct: done: " PF_MEMBERSHIP,
1692 PA_MEMBERSHIP(membership));
1694 return (membership);
1697 struct membership *virtual_enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child));
1700 virtual_enlist_entity_direct(parent, child)
1704 struct membership *membership;
1706 if (debug & DEBUG_CFGEVAL_FLAG)
1707 report(LOG_DEBUG, "virtual_enlist_entity_direct: the following enlist will be VIRTUAL...");
1709 membership = enlist_entity_direct(parent, child, NULL /* when */);
1713 check_request_scan_membership(membership, 0);
1714 tac_list_addtail(&request_virtual_membership_list, &membership->request_scan.virtual_membership_node);
1716 return (membership);
1719 /* returns given 'entity' or NULL if already visited */
1721 void (*value_scan_forward_seen_hook) TAC_ARGS((struct membership *membership));
1723 static ENTITY *value_scan_forward TAC_ARGS((struct membership *membership));
1726 value_scan_forward(membership)
1727 struct membership *membership;
1729 ENTITY *parent_entity;
1731 if (debug & DEBUG_CFGEVAL_FLAG)
1732 report(LOG_DEBUG, "value_scan_forward: from " PF_MEMBERSHIP " try forward...",
1733 PA_MEMBERSHIP(membership));
1735 parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1737 if (ER_TRUE != expr_eval(membership->when)) {
1738 if (debug & DEBUG_CFGEVAL_FLAG)
1739 report(LOG_DEBUG, "value_scan_forward: forward NOT successful due to failed 'when' evaluation.");
1742 check_value_scan_entity(parent_entity, 0);
1743 if (parent_entity->value_scan.seen) {
1744 if (debug & DEBUG_CFGEVAL_FLAG)
1745 report(LOG_DEBUG, "value_scan_forward: forward NOT successful as the parent " PF_ENTITY " was already seen this value scan.",
1746 PA_ENTITY(parent_entity));
1747 if (value_scan_forward_seen_hook)
1748 (*value_scan_forward_seen_hook)(membership);
1751 parent_entity->value_scan.seen = 1;
1752 parent_entity->value_scan.from = membership;
1754 if (debug & DEBUG_CFGEVAL_FLAG)
1755 report(LOG_DEBUG, "value_scan_forward: forward SUCCESSFUL to parent " PF_ENTITY,
1756 PA_ENTITY(parent_entity));
1757 return (parent_entity);
1760 struct membership *value_scan_backward TAC_ARGS((ENTITY *entity));
1763 value_scan_backward(entity)
1766 if (debug & DEBUG_CFGEVAL_FLAG)
1767 report(LOG_DEBUG, "value_scan_backward: from " PF_ENTITY " went back to " PF_MEMBERSHIP,
1768 PA_ENTITY(entity), PA_MEMBERSHIP(entity->value_scan.from));
1770 #ifdef SCAN_PARANOIA
1771 if (entity->value_scan.seq != value_scan_seq) {
1772 report(LOG_ERR, "entity value_scan NOT up-to-date in value_scan_backward");
1777 return (entity->value_scan.from);
1780 /* Scan the entity graph and return each node found.
1781 'when' conditions for graph connections are respected,
1782 looping is correctly prevented.
1785 enum value_scan_func_result value_scan_entity TAC_ARGS((ENTITY *entity, int recurse, value_scan_func_t func, void *func_data));
1787 enum value_scan_func_result
1788 value_scan_entity(entity, recurse, func, func_data)
1791 value_scan_func_t func;
1794 enum value_scan_func_result vsfr;
1795 struct tac_list_node *membership_node;
1797 if (debug & DEBUG_CFGEVAL_FLAG)
1798 report(LOG_DEBUG, "value_scan_entity: " PF_ENTITY ", recurse=%d",
1799 PA_ENTITY(entity), recurse);
1801 vsfr=(*func)(entity,func_data);
1803 if (debug & DEBUG_CFGEVAL_FLAG)
1804 report(LOG_DEBUG, "value_scan_entity: root func-> " PF_VSFR,
1807 if (vsfr != VSFR_CONTINUE) {
1808 if (debug & DEBUG_CFGEVAL_FLAG)
1809 report(LOG_DEBUG, "value_scan_entity: finishing as root func didn't return VSFR_CONTINUE");
1813 if (debug & DEBUG_CFGEVAL_FLAG)
1814 report(LOG_DEBUG, "value_scan_entity: finishing as recurse not ordered");
1818 value_scan_begin(entity);
1819 membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1820 if (!membership_node) {
1821 if (debug & DEBUG_CFGEVAL_FLAG)
1822 report(LOG_DEBUG, "value_scan_entity: finishing as no parent entities of root");
1823 return (VSFR_CONTINUE); /* no parent entities */
1827 struct membership *membership = CHILD_NODE_TO_MEMBERSHIP(membership_node);
1829 if (debug & DEBUG_CFGEVAL_FLAG)
1830 report(LOG_DEBUG, "value_scan_entity: trace loop start: " PF_MEMBERSHIP,
1831 PA_MEMBERSHIP(membership));
1833 entity = value_scan_forward(membership);
1835 if (debug & DEBUG_CFGEVAL_FLAG)
1836 report(LOG_DEBUG, "value_scan_entity: successful recurse to " PF_ENTITY,
1839 vsfr=(*func)(entity,func_data);
1841 if (debug & DEBUG_CFGEVAL_FLAG)
1842 report(LOG_DEBUG, "value_scan_entity: func(" PF_ENTITY ")-> " PF_VSFR,
1843 PA_ENTITY(entity), PA_VSFR(vsfr));
1845 if (vsfr == VSFR_FOUND) {
1846 if (debug & DEBUG_CFGEVAL_FLAG)
1847 report(LOG_DEBUG, "value_scan_entity: finishing as func returned VSFR_FOUND");
1850 if (vsfr == VSFR_CONTINUE)
1851 membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1853 if (!entity || vsfr == VSFR_STOP) {
1854 ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1856 entity = MEMBERSHIP_TO_CHILD_ENTITY(membership); /* for retreat from the LAST membership */
1858 if (debug & DEBUG_CFGEVAL_FLAG)
1859 report(LOG_DEBUG, "value_scan_entity: unsuccessful recurse to " PF_ENTITY ", tracing back through child " PF_ENTITY,
1860 PA_ENTITY(parent_entity), PA_ENTITY(entity));
1862 membership_node = tac_list_node_next(&membership->child_node);
1865 while (!membership_node) {
1866 membership = value_scan_backward(entity);
1868 if (debug & DEBUG_CFGEVAL_FLAG)
1869 report(LOG_DEBUG, "value_scan_entity: finishing as all nodes were scanned");
1870 return (VSFR_CONTINUE); /* FINISH */
1873 entity = MEMBERSHIP_TO_CHILD_ENTITY(membership); /* for retreat from the LAST membership */
1875 if (debug & DEBUG_CFGEVAL_FLAG)
1876 report(LOG_DEBUG, "value_scan_entity: backward retreat ('next' chase) "
1877 "through " PF_MEMBERSHIP " to child " PF_ENTITY,
1878 PA_MEMBERSHIP(membership), PA_ENTITY(entity));
1880 membership_node = tac_list_node_next(&membership->child_node);