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