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 if (expr_sink_internal(expr->u.not.child, membership, expr /* parent */))
388 if (expr_sink_internal(expr->u.and_or.child_first, membership, expr /* parent */))
395 tac_list_node_init(&expr->eval_scan.u.entity.notify_expr_node);
396 expr->u.entity.entity = entity_lookup(expr->type, expr->u.entity.name);
397 if (!expr->u.entity.entity) {
398 report(LOG_ERR, "referenced entity %s %s not found on line %d",
399 entity_type_to_string(expr->type), expr->u.entity.name, expr->line);
402 free((char *) expr->u.entity.name);
403 expr->u.entity.name = NULL;
407 report(LOG_ERR, "Illegal node type %d for expr_sink", expr->type);
414 static int expr_sink TAC_ARGS((struct expr *expr, struct membership *membership));
417 expr_sink(expr, membership)
419 struct membership *membership;
421 return (expr_sink_internal(expr, membership, NULL /* parent */));
424 static struct expr *expr_sink_register_head = NULL;
426 void expr_sink_register TAC_ARGS((struct expr *expr));
429 expr_sink_register(expr)
435 expr->parent = expr_sink_register_head;
436 expr_sink_register_head = expr;
439 int expr_sink_commit TAC_ARGS((void));
446 while ((expr = expr_sink_register_head)) {
447 expr_sink_register_head = expr->parent;
448 /* 'expr->parent' not defined for 'expr_sink()' */
450 if (expr_sink(expr, NULL /* membership */))
451 return (1); /* failure */
453 return (0); /* success */
456 struct expr *dupl_expr TAC_ARGS((const struct expr *in));
460 const struct expr *in;
462 struct expr *expr_root = NULL;
463 struct expr **succ_exprp = &expr_root;
466 for (;in; in=in->next) {
467 expr = (struct expr *) tac_malloc(sizeof(struct expr));
468 expr->line = in->line;
470 expr->type = in->type;
474 if (in->u.not.child && in->u.not.child->type==S_not) {
476 expr = dupl_expr(in->u.not.child->u.not.child);
478 expr->u.not.child = dupl_expr(in->u.not.child);
483 if (!in->u.and_or.child_first) {
486 } else if (!in->u.and_or.child_first->next) {
488 expr = dupl_expr(in->u.and_or.child_first);
490 expr->u.and_or.child_first = dupl_expr(in->u.and_or.child_first);
496 if (in->u.entity.name)
497 expr->u.entity.name = tac_strdup(in->u.entity.name);
499 expr->u.entity.name = NULL;
500 expr->u.entity.entity = in->u.entity.entity;
504 report(LOG_ERR, "Illegal node type %d for dupl_expr", in->type);
505 free_expr(expr_root);
510 succ_exprp = &expr->next;
516 /* 'check_*_scan_*()' section:
519 static void check_request_scan_expr TAC_ARGS((struct expr *expr, int flush));
522 check_request_scan_expr(expr, flush)
526 #if REPORT_CHECK_SCAN_VERBOSE
527 if (debug & DEBUG_CFGEVAL_FLAG)
528 report(LOG_DEBUG, "check_request_scan_expr: " PF_EXPR " (" PF_ERESULT_EXPR ")",
529 PA_EXPR(expr), PA_ERESULT_EXPR(expr));
532 if (!flush && expr->request_scan.seq == request_scan_seq)
533 return; /* up to date */
535 expr->request_scan.result = ER_UNKNOWN;
536 expr->request_scan.loop_reported = 0;
537 expr->request_scan.seq = request_scan_seq;
539 if (debug & DEBUG_CFGEVAL_FLAG)
540 report(LOG_DEBUG, "check_request_scan_expr: done: " PF_EXPR,
544 static void check_eval_scan_expr TAC_ARGS((struct expr *expr, int flush));
547 check_eval_scan_expr(expr, flush)
551 #if REPORT_CHECK_SCAN_VERBOSE
552 if (debug & DEBUG_CFGEVAL_FLAG)
553 report(LOG_DEBUG, "check_eval_scan_expr: " PF_EXPR,
557 if (!flush && expr->eval_scan.seq == eval_scan_seq)
558 return; /* up to date */
559 check_request_scan_expr(expr, 0);
561 switch (expr->type) {
567 if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node) == &eval_notified_expr_list) {
568 report(LOG_ERR, "INTERNAL: expr still connected to eval_notified_expr_list in check_eval_scan_expr");
569 } else if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node)) {
570 ENTITY *notifying_entity = EXPR_ENTITY_TO_NOTIFYING_ENTITY(expr);
572 if (notifying_entity != expr->u.entity.entity)
573 report(LOG_ERR, "INTERNAL: expr->notify_expr_node->list != expr->entity");
574 if (notifying_entity->eval_scan.seq != expr->eval_scan.seq)
575 report(LOG_ERR, "INTERNAL: entity seq != expr node seq");
576 tac_list_node_remove(&expr->eval_scan.u.entity.notify_expr_node);
578 #else /* SCAN_PARANOIA */
579 tac_list_node_init(&expr->eval_scan.u.entity.notify_expr_node);
580 #endif /* SCAN_PARANOIA */
584 expr->eval_scan.seq = eval_scan_seq; /* used above, keep as LAST! */
586 if (debug & DEBUG_CFGEVAL_FLAG)
587 report(LOG_DEBUG, "check_eval_scan_expr: done: " PF_EXPR,
591 static void check_request_scan_membership TAC_ARGS((struct membership *membership, int flush));
594 check_request_scan_membership(membership, flush)
595 struct membership *membership;
598 #if REPORT_CHECK_SCAN_VERBOSE
599 if (debug & DEBUG_CFGEVAL_FLAG)
600 report(LOG_DEBUG, "check_request_scan_membership: " PF_MEMBERSHIP " (" PF_ERESULT_MEMBERSHIP ")",
601 PA_MEMBERSHIP(membership), PA_ERESULT_MEMBERSHIP(membership));
604 if (!flush && membership->request_scan.seq == request_scan_seq)
605 return; /* up to date */
609 struct tac_list *virtual_list = tac_list_node_get_list(&membership->request_scan.virtual_membership_node);
611 if (virtual_list && virtual_list != &request_virtual_membership_list)
612 report(LOG_ERR, "Illegal list in membership->virtual_membership_node.list");
614 tac_list_node_remove(&membership->request_scan.virtual_membership_node);
616 #else /* SCAN_PARANOIA */
617 tac_list_node_init(&membership->request_scan.virtual_membership_node);
618 #endif /* SCAN_PARANOIA */
620 membership->request_scan.seq = request_scan_seq; /* used above, keep as LAST! */
622 if (debug & DEBUG_CFGEVAL_FLAG)
623 report(LOG_DEBUG, "check_request_scan_membership: done: " PF_MEMBERSHIP,
624 PA_MEMBERSHIP(membership));
627 /* we are cross-checking (membership<->parent entity)! */
629 static void check_eval_scan_membership TAC_ARGS((struct membership *membership, int flush));
632 check_eval_scan_membership(membership, flush)
633 struct membership *membership;
636 #if REPORT_CHECK_SCAN_VERBOSE
637 if (debug & DEBUG_CFGEVAL_FLAG)
638 report(LOG_DEBUG, "check_eval_scan_membership: " PF_MEMBERSHIP,
639 PA_MEMBERSHIP(membership));
642 if (!flush && membership->eval_scan.seq == eval_scan_seq)
643 return; /* up to date */
644 check_request_scan_membership(membership, 0);
646 membership->eval_scan.unsolved = 1;
647 membership->eval_scan.seq = eval_scan_seq;
649 if (debug & DEBUG_CFGEVAL_FLAG)
650 report(LOG_DEBUG, "check_eval_scan_membership: done: " PF_MEMBERSHIP,
651 PA_MEMBERSHIP(membership));
654 static void check_request_scan_entity TAC_ARGS((ENTITY *entity, int flush));
657 check_request_scan_entity(entity, flush)
661 #if REPORT_CHECK_SCAN_VERBOSE
662 if (debug & DEBUG_CFGEVAL_FLAG)
663 report(LOG_DEBUG, "check_request_scan_entity: " PF_ENTITY " (" PF_ERESULT_ENTITY ")",
664 PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
667 if (!flush && entity->request_scan.seq == request_scan_seq)
670 entity->request_scan.belongs = ER_UNKNOWN;
671 entity->request_scan.seq = request_scan_seq;
673 if (debug & DEBUG_CFGEVAL_FLAG)
674 report(LOG_DEBUG, "check_request_scan_entity: done: " PF_ENTITY,
678 static void check_value_scan_entity TAC_ARGS((ENTITY *entity, int flush));
681 check_value_scan_entity(entity, flush)
685 #if REPORT_CHECK_SCAN_VERBOSE
686 if (debug & DEBUG_CFGEVAL_FLAG)
687 report(LOG_DEBUG, "check_value_scan_entity: " PF_ENTITY,
691 if (!flush && entity->value_scan.seq == value_scan_seq)
693 check_request_scan_entity(entity, 0);
695 entity->value_scan.seen = 0;
696 entity->value_scan.from = NULL;
697 entity->value_scan.seq = value_scan_seq;
699 if (debug & DEBUG_CFGEVAL_FLAG)
700 report(LOG_DEBUG, "check_value_scan_entity: done: " PF_ENTITY,
704 static void check_eval_scan_entity TAC_ARGS((ENTITY *entity, int flush));
707 check_eval_scan_entity(entity, flush)
711 struct tac_list_node *child_membership_parent_node;
713 #if REPORT_CHECK_SCAN_VERBOSE
714 if (debug & DEBUG_CFGEVAL_FLAG)
715 report(LOG_DEBUG, "check_eval_scan_entity: " PF_ENTITY,
719 if (!flush && entity->eval_scan.seq == eval_scan_seq)
720 return; /* up to date */
721 check_value_scan_entity(entity, 0);
723 entity->eval_scan.unsolved_to_child_membership_num = entity->to_child_membership_num;
725 if ((child_membership_parent_node = tac_list_first_node(&entity->to_child_membership_list))) {
726 struct membership *child_membership = PARENT_NODE_TO_MEMBERSHIP(child_membership_parent_node);
728 entity->eval_scan.unsolved_to_child_membership_first = child_membership;
730 entity->eval_scan.unsolved_to_child_membership_first = NULL;
734 struct tac_list_node *notify_expr_node;
736 while ((notify_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
737 struct expr *notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(notify_expr_node);
739 if (notify_expr->u.entity.entity != entity)
740 report(LOG_ERR, "INTERNAL: notify_expr->entity != entity");
741 if (notify_expr->eval_scan.seq != entity->eval_scan.seq)
742 report(LOG_ERR, "INTERNAL: notify_expr seq != entity seq");
743 tac_list_node_remove(notify_expr_node);
746 if (tac_list_node_get_list(&entity->eval_scan.pending_entity_node))
747 tac_list_node_remove(&entity->eval_scan.pending_entity_node);
749 #else /* SCAN_PARANOIA */
750 tac_list_init(&entity->eval_scan.notify_expr_list);
751 tac_list_node_init(&entity->eval_scan.pending_entity_node);
752 #endif /* SCAN_PARANOIA */
754 entity->eval_scan.seq = eval_scan_seq; /* used above, keep as LAST! */
756 if (debug & DEBUG_CFGEVAL_FLAG)
757 report(LOG_DEBUG, "check_eval_scan_entity: done: " PF_ENTITY,
762 /* invalidation managing section (for '*_scan_begin()'):
765 /* this will happen once upon 'unsigned' overflow, ehm */
767 #define INVALIDATE_SEQ_PTR(object,ptr) \
768 (G_STRUCT_MEMBER(unsigned, ptr, invalidate_scan_##object##_table[what]) = (unsigned) -1)
769 #define INVALIDATE_SEQ(object) \
770 (INVALIDATE_SEQ_PTR(object,object))
772 static const long invalidate_scan_expr_table[IS_MAX]={
773 G_STRUCT_OFFSET(struct expr, request_scan.seq),
775 G_STRUCT_OFFSET(struct expr, eval_scan.seq)};
777 static void invalidate_scan_expr TAC_ARGS((struct expr *expr,enum invalidate_scan what));
780 invalidate_scan_expr(expr_single, what)
781 struct expr *expr_single;
782 enum invalidate_scan what;
784 struct expr *expr_parent, *expr_child;
787 report(LOG_ERR, "INTERNAL: NULL input expressions not support by invalidate_scan_expr");
790 if (expr_single->parent) {
791 report(LOG_ERR, "INTERNAL: non-root expressions not supported by invalidate_scan_expr");
795 /* TOP->DOWN scanner: */
798 INVALIDATE_SEQ_PTR(expr,expr_single);
799 expr_parent = expr_single;
801 switch (expr_parent->type) {
804 expr_child = expr_parent->u.not.child;
809 expr_child = expr_parent->u.and_or.child_first;
815 expr_child = NULL; /* no child exists */
819 report(LOG_ERR, "Illegal child node type %d for invalidate_scan_expr", expr_parent->type);
822 } while ((expr_single = expr_child));
823 /* expr_child==NULL, we have only expr_parent: */
825 expr_child = expr_parent;
827 /* we have only expr_child: */
828 /* BOTTOM->UP scanner */
830 if ((expr_single = expr_child->next))
832 expr_parent = expr_child->parent;
833 } while ((expr_child = expr_parent));
836 static const long invalidate_scan_membership_table[IS_MAX]={
837 G_STRUCT_OFFSET(struct membership, request_scan.seq),
839 G_STRUCT_OFFSET(struct membership, eval_scan.seq)};
841 static void invalidate_scan_membership TAC_ARGS((struct membership *membership,enum invalidate_scan what));
844 invalidate_scan_membership(membership, what)
845 struct membership *membership;
846 enum invalidate_scan what;
848 INVALIDATE_SEQ(membership);
850 if (membership->when)
851 invalidate_scan_expr(membership->when, what);
854 static const long invalidate_scan_entity_table[IS_MAX]={
855 G_STRUCT_OFFSET(ENTITY, request_scan.seq),
856 G_STRUCT_OFFSET(ENTITY, value_scan.seq),
857 G_STRUCT_OFFSET(ENTITY, eval_scan.seq)};
859 static void invalidate_scan_entity TAC_ARGS((ENTITY *entity,enum invalidate_scan what));
862 invalidate_scan_entity(entity, what)
864 enum invalidate_scan what;
866 struct tac_list_node *child_membership_node;
867 struct membership *child_membership;
869 INVALIDATE_SEQ(entity);
871 if (what==IS_VALUE) /* optimalization */
875 child_membership_node = tac_list_first_node(&entity->to_child_membership_list);
876 child_membership_node;
877 child_membership_node = tac_list_node_next(&child_membership->parent_node)
879 child_membership = PARENT_NODE_TO_MEMBERSHIP(child_membership_node);
880 invalidate_scan_membership(child_membership, what);
884 void scan_invalidate_entities_hashtable TAC_ARGS((void **hashtable, enum invalidate_scan what));
887 scan_invalidate_entities_hashtable(hashtable, what)
889 enum invalidate_scan what;
894 for (i = 0; i < HASH_TAB_SIZE; i++)
895 for (entity = (ENTITY *) hashtable[i]; entity; entity = entity->hash)
896 invalidate_scan_entity(entity, what);
899 /* '*_scan_begin()' section:
902 void request_scan_begin TAC_ARGS((void));
908 static int inited = 0;
909 #endif /* SCAN_PARANOIA */
911 if (debug & DEBUG_CFGEVAL_FLAG)
912 report(LOG_DEBUG, "request_scan_begin:");
914 request_scan_user_known = 0;
916 if (!++request_scan_seq)
917 scan_invalidate_entities(IS_REQUEST);
921 #endif /* SCAN_PARANOIA */
922 tac_list_init(&request_virtual_membership_list);
926 struct tac_list_node *virtual_membership_node;
928 while ((virtual_membership_node = tac_list_first_node(&request_virtual_membership_list))) {
929 struct membership *virtual_membership = VIRTUAL_MEMBERSHIP_NODE_TO_MEMBERSHIP(virtual_membership_node);
931 if (virtual_membership->request_scan.seq == request_scan_seq)
932 report(LOG_ERR, "INTERNAL: request_virtual_membership_list membership seq == ++request_scan_seq in request_scan_begin");
933 tac_list_node_remove(virtual_membership_node);
934 unlink_membership(virtual_membership);
935 free_membership(virtual_membership);
938 #endif /* SCAN_PARANOIA */
941 static void value_scan_begin TAC_ARGS((ENTITY *entity));
944 value_scan_begin(entity)
947 if (debug & DEBUG_CFGEVAL_FLAG)
948 report(LOG_DEBUG, "value_scan_begin:");
950 if (!++value_scan_seq)
951 scan_invalidate_entities(IS_VALUE);
953 check_value_scan_entity(entity, 0); /* sure as seq invalidated */
954 /* assumed (entity->value_scan.from == NULL) */
959 static void eval_scan_begin_pending_entity_node TAC_ARGS((struct tac_list_node *pending_entity_node));
962 eval_scan_begin_pending_entity_node(pending_entity_node)
963 struct tac_list_node *pending_entity_node;
965 ENTITY *pending_entity = PENDING_ENTITY_NODE_TO_ENTITY(pending_entity_node);
967 if (pending_entity->eval_scan.seq == eval_scan_seq)
968 report(LOG_ERR, "INTERNAL: eval_{pending}_entity_list entity seq == ++eval_scan_seq in eval_scan_begin");
970 tac_list_node_remove(pending_entity_node);
973 #endif /* SCAN_PARANOIA */
975 static void eval_scan_begin TAC_ARGS((void));
981 static int inited = 0;
982 #endif /* SCAN_PARANOIA */
984 if (debug & DEBUG_CFGEVAL_FLAG)
985 report(LOG_DEBUG, "eval_scan_begin:");
987 if (!++eval_scan_seq)
988 scan_invalidate_entities(IS_EVAL);
992 #endif /* SCAN_PARANOIA */
993 tac_list_init(&eval_kicked_entity_list);
994 tac_list_init(&eval_destroy_entity_list);
995 tac_list_init(&eval_notified_expr_list);
999 struct tac_list_node *pending_entity_node;
1000 struct tac_list_node *notify_expr_node;
1002 while ((pending_entity_node = tac_list_first_node(&eval_kicked_entity_list)))
1003 eval_scan_begin_pending_entity_node(pending_entity_node);
1004 while ((pending_entity_node = tac_list_first_node(&eval_destroy_entity_list)))
1005 eval_scan_begin_pending_entity_node(pending_entity_node);
1007 while ((notify_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
1008 struct expr *notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(notify_expr_node);
1010 if (notify_expr->eval_scan.seq == eval_scan_seq)
1011 report(LOG_ERR, "INTERNAL: eval_notified_expr_list expr seq == ++eval_scan_seq in eval_scan_begin");
1013 tac_list_node_remove(notify_expr_node);
1016 #endif /* SCAN_PARANOIA */
1019 /* 'priority=0' => addtail - used for WANTED entities
1020 * 'priority=1' => addhead - used for SOLVED entities
1021 * It may be better to do insert it AFTER all currently solved
1022 * entities but may be not but who cares...
1025 static void register_kicked_entity TAC_ARGS((ENTITY *entity, int priority));
1027 static void register_kicked_entity(entity, priority)
1031 struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
1033 check_eval_scan_entity(entity, 0);
1035 if (tac_list_node_get_list(pending_entity_node) == &eval_destroy_entity_list) {
1036 tac_list_node_remove (pending_entity_node);
1037 if (debug & DEBUG_CFGEVAL_FLAG)
1038 report(LOG_DEBUG, "register_kicked_entity: REMOVED " PF_ENTITY " from eval_DESTROY_entity_list",
1041 if (tac_list_node_get_list(pending_entity_node) == NULL) {
1043 tac_list_addhead(&eval_kicked_entity_list, pending_entity_node);
1045 tac_list_addtail(&eval_kicked_entity_list, pending_entity_node);
1046 if (debug & DEBUG_CFGEVAL_FLAG)
1047 report(LOG_DEBUG, "register_kicked_entity: REGISTERED " PF_ENTITY " to eval_KICKED_entity_list (priority=%s)",
1048 PA_ENTITY(entity), (priority ? "YES" : "NO"));
1050 #ifdef SCAN_PARANOIA
1051 if ((tac_list_node_get_list(pending_entity_node) != &eval_kicked_entity_list)) {
1052 report(LOG_ERR, "Illegal list in entity->pending_entity_node.list");
1058 /* check_eval_scan_*() is assumed both for "expr" and for "entity" ! */
1060 static void expr_eval_notify_expr TAC_ARGS((struct expr *expr));
1063 expr_eval_notify_expr(expr)
1066 ENTITY *entity = expr->u.entity.entity;
1068 if (debug & DEBUG_CFGEVAL_FLAG)
1069 report(LOG_DEBUG, "expr_eval_notify_expr: REGISTERED notify " PF_EXPR " when " PF_ENTITY " is known",
1070 PA_EXPR(expr), PA_ENTITY(entity));
1072 if (tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node)) {
1073 #ifdef SCAN_PARANOIA
1074 if (&entity->eval_scan.notify_expr_list
1075 != tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
1076 report(LOG_ERR, "Another " PF_ENTITY " already registered in notify node of " PF_EXPR,
1077 PA_ENTITY(EXPR_ENTITY_TO_NOTIFYING_ENTITY(expr)), PA_EXPR(expr));
1082 tac_list_addtail(&entity->eval_scan.notify_expr_list,
1083 &expr->eval_scan.u.entity.notify_expr_node);
1085 register_kicked_entity(entity, 0 /* priority */);
1088 /* check_eval_scan_*() is assumed for "expr" ! */
1090 static void expr_eval_notify_expr_remove_internal TAC_ARGS((struct expr *expr));
1093 expr_eval_notify_expr_remove_internal(expr)
1096 if (debug & DEBUG_CFGEVAL_FLAG)
1097 report(LOG_DEBUG, "expr_eval_notify_expr_remove_internal: no longer interested in " PF_EXPR,
1102 if (expr->eval_scan.seq != eval_scan_seq)
1104 if (expr->request_scan.result != ER_UNKNOWN)
1107 switch (expr->type) {
1110 expr_eval_notify_expr_remove_internal(expr->u.not.child);
1117 for (child=expr->u.and_or.child_first; child; child=child->next)
1118 expr_eval_notify_expr_remove_internal(child);
1124 ENTITY *entity = expr->u.entity.entity;
1125 struct tac_list_node *pending_entity_node = &entity->eval_scan.pending_entity_node;
1127 if (!tac_list_node_get_list(&expr->eval_scan.u.entity.notify_expr_node))
1130 tac_list_node_remove(&expr->eval_scan.u.entity.notify_expr_node);
1131 if (tac_list_first_node(&entity->eval_scan.notify_expr_list))
1133 /* no one is further interested in "entity" */
1135 if ((tac_list_node_get_list(pending_entity_node) == &eval_kicked_entity_list)) {
1136 tac_list_node_remove (pending_entity_node);
1137 if (debug & DEBUG_CFGEVAL_FLAG)
1138 report(LOG_DEBUG, "expr_eval_notify_expr: REMOVED " PF_ENTITY " from eval_KICKED_entity_list",
1141 if (tac_list_node_get_list(pending_entity_node) == NULL) {
1142 tac_list_addtail(&eval_destroy_entity_list, pending_entity_node);
1143 if (debug & DEBUG_CFGEVAL_FLAG)
1144 report(LOG_DEBUG, "expr_eval_notify_expr: REGISTERED " PF_ENTITY " to eval_DESTROY_entity_list",
1147 #ifdef SCAN_PARANOIA
1148 if (tac_list_node_get_list(pending_entity_node) != &eval_destroy_entity_list) {
1149 report(LOG_ERR, "Illegal list in entity->pending_entity_node.list");
1157 report(LOG_ERR, "Illegal node type %d for expr_eval_notify_expr_remove", expr->type);
1162 static void expr_eval_notify_expr_flush_destroy_entity_list TAC_ARGS((void));
1164 static void expr_eval_notify_expr_flush_destroy_entity_list()
1166 struct tac_list_node *destroy_entity_node;
1168 while ((destroy_entity_node = tac_list_first_node(&eval_destroy_entity_list))) {
1169 ENTITY *destroy_entity = PENDING_ENTITY_NODE_TO_ENTITY(destroy_entity_node);
1170 struct tac_list_node *destroy_notify_expr_node;
1172 if (debug & DEBUG_CFGEVAL_FLAG)
1173 report(LOG_DEBUG, "expr_eval_notify_expr_flush_destroy_entity_list: PROCESSING " PF_ENTITY " from eval_DESTROY_entity_list",
1174 PA_ENTITY(destroy_entity));
1176 while ((destroy_notify_expr_node = tac_list_first_node(&destroy_entity->eval_scan.notify_expr_list))) {
1177 struct expr *destroy_notify_expr = NOTIFY_EXPR_NODE_TO_EXPR(destroy_notify_expr_node);
1179 expr_eval_notify_expr_remove_internal(destroy_notify_expr);
1184 static void expr_eval_notify_expr_remove TAC_ARGS((struct expr *expr));
1187 expr_eval_notify_expr_remove(expr)
1190 if (debug & DEBUG_CFGEVAL_FLAG)
1191 report(LOG_DEBUG, "expr_eval_notify_expr_remove: no longer interested in " PF_EXPR,
1194 expr_eval_notify_expr_remove_internal(expr);
1195 expr_eval_notify_expr_flush_destroy_entity_list();
1198 /* It would be very nice to try to optimize the expression before evaluation.
1200 We are not interested in some CPU time complexity of the expression.
1201 But we would be very happy to discard any user/host/group membership
1202 dependencies (our 'variables'). Unfortunately such optimization is
1203 NP problem (classification by courtesy of Daniel Kral) so it is considered
1204 too expensive for us.
1206 TODO in future: Full NP optimization for small number of variables and/or
1207 heuristic optimizations for complex expressions.
1210 static enum eval_result expr_eval_immediate TAC_ARGS((struct expr *expr_single));
1212 static enum eval_result
1213 expr_eval_immediate(expr_single)
1214 struct expr *expr_single;
1216 struct expr *expr_child, *expr_parent;
1217 enum eval_result result_child, result_parent = 0 /* GCC paranoia */;
1219 if (debug & DEBUG_CFGEVAL_FLAG)
1220 report(LOG_DEBUG, "expr_eval_immediate: " PF_EXPR,
1221 PA_EXPR(expr_single));
1226 /* TOP->DOWN scanner: */
1229 enum eval_result result_single;
1231 if (debug & DEBUG_CFGEVAL_FLAG)
1232 report(LOG_DEBUG, "expr_eval_immediate: top_down start: " PF_EXPR,
1233 PA_EXPR(expr_single));
1235 check_eval_scan_expr(expr_single, 0);
1236 result_single = expr_single->request_scan.result;
1237 if (result_single != ER_UNKNOWN)
1239 switch (expr_single->type) {
1242 expr_single = expr_single->u.not.child;
1247 expr_single = expr_single->u.and_or.child_first;
1253 ENTITY *entity = expr_single->u.entity.entity;
1255 check_eval_scan_entity(entity, 0);
1257 if (entity->request_scan.belongs == ER_UNKNOWN)
1258 expr_eval_notify_expr(expr_single);
1260 result_single = entity->request_scan.belongs;
1264 report(LOG_ERR, "Illegal child node type %d for expr_eval", expr_single->type);
1265 return (ER_UNKNOWN);
1268 expr_single->request_scan.result = result_single;
1272 /* BOTTOM->UP scanner: */
1274 if (debug & DEBUG_CFGEVAL_FLAG)
1275 report(LOG_DEBUG, "expr_eval_immediate: bottom_up start: " PF_EXPR,
1276 PA_EXPR(expr_single));
1278 expr_parent = expr_single->parent;
1281 if (expr_parent->eval_scan.seq != eval_scan_seq) {
1282 report(LOG_ERR, "INTERNAL: Parent expr node eval_scan NOT up-to-date");
1283 return (ER_UNKNOWN);
1285 if (expr_parent->request_scan.seq != request_scan_seq) {
1286 report(LOG_ERR, "INTERNAL: Parent expr node request_scan NOT up-to-date");
1287 return (ER_UNKNOWN);
1289 if (expr_parent->request_scan.result != ER_UNKNOWN) {
1290 report(LOG_WARNING, "INTERNAL-WARNING: Parent expr node already known, wasteful eval occured");
1291 return (ER_UNKNOWN);
1294 expr_child = expr_single;
1295 result_child = expr_child->request_scan.result;
1297 if (debug & DEBUG_CFGEVAL_FLAG)
1298 report(LOG_DEBUG, "expr_eval_immediate: bottom_up switch: child=" PF_EXPR ",parent=" PF_EXPR,
1299 PA_EXPR(expr_child), PA_EXPR(expr_parent));
1301 switch (expr_parent->type) {
1304 switch (result_child) {
1305 case ER_UNKNOWN: result_parent = ER_UNKNOWN; break;
1306 case ER_FALSE: result_parent = ER_TRUE; break;
1307 case ER_TRUE: result_parent = ER_FALSE; break;
1313 enum eval_result veto = (expr_parent->type==S_and ? ER_FALSE : ER_TRUE );
1314 enum eval_result consent = (expr_parent->type==S_and ? ER_TRUE : ER_FALSE);
1316 if (result_child == veto)
1317 result_parent = veto;
1318 else if (result_child == ER_UNKNOWN || result_child == consent) {
1319 if (expr_child->next) {
1320 expr_single = expr_child->next;
1321 if (debug & DEBUG_CFGEVAL_FLAG)
1322 report(LOG_DEBUG, "expr_eval_immediate: bottom_up and_or: traversed to and_or next: " PF_EXPR,
1323 PA_EXPR(expr_single));
1327 if (debug & DEBUG_CFGEVAL_FLAG)
1328 report(LOG_DEBUG, "expr_eval_immediate: bottom_up and_or: full scan: " PF_EXPR,
1329 PA_EXPR(expr_single));
1331 /* It would be nice to pretend that all 'veto' decisions already made in the child
1332 * had to set our 'result' to the correct value. But 'consent' decisions don't set
1333 * us and the behaviour of auto-set from the child in 'veto' case may get changed
1334 * in the future versions.
1335 * So we rather don't depend on it.
1336 * This overhead doesn't change altgorithmic complexity anyway.
1338 result_parent = consent;
1339 for (expr_child = expr_parent->u.and_or.child_first; expr_child; expr_child = expr_child->next)
1341 check_eval_scan_expr(expr_child, 0); /* shouldn't be needed */
1342 if (expr_child->request_scan.result == ER_UNKNOWN)
1343 result_parent = ER_UNKNOWN; /* assumed (result_parent != veto) */
1344 else if (expr_child->request_scan.result == veto) {
1345 result_parent = veto;
1354 report(LOG_ERR, "Illegal parent node type %d for expr_eval", expr_parent->type);
1355 return (ER_UNKNOWN);
1358 if (debug & DEBUG_CFGEVAL_FLAG)
1359 report(LOG_DEBUG, "expr_eval_immediate: bottom_up end: child=" PF_EXPR ",parent=" PF_EXPR,
1360 PA_EXPR(expr_child), PA_EXPR(expr_parent));
1362 if (result_parent != ER_UNKNOWN) {
1363 expr_parent->request_scan.result = result_parent;
1364 /* we no longer need any notifications from entities to solve sub-expression */
1365 expr_eval_notify_expr_remove(expr_parent);
1368 expr_single = expr_parent;
1370 /* The whole expression has been scanned to its root, we have "expr_single" */
1372 if (debug & DEBUG_CFGEVAL_FLAG)
1373 report(LOG_DEBUG, "expr_eval_immediate: done: " PF_EXPR,
1374 PA_EXPR(expr_single));
1376 return (expr_single->request_scan.result);
1379 static void membership_solved TAC_ARGS((struct membership *membership));
1382 membership_solved(membership)
1383 struct membership *membership;
1385 ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1387 check_request_scan_entity(parent_entity, 0);
1389 #ifdef SCAN_PARANOIA
1390 if (!membership->eval_scan.unsolved) {
1391 report(LOG_ERR, "INTERNAL: membership already solved in membership_solved");
1396 membership->eval_scan.unsolved = 0;
1398 #ifdef SCAN_PARANOIA
1399 if (!parent_entity->eval_scan.unsolved_to_child_membership_num) {
1400 report(LOG_ERR, "INTERNAL: unsolved_to_child_membership_num-- == 0 in membership_solved");
1401 parent_entity->eval_scan.unsolved_to_child_membership_num++;
1404 parent_entity->eval_scan.unsolved_to_child_membership_num--;
1406 if (!parent_entity->eval_scan.unsolved_to_child_membership_num
1407 && parent_entity->request_scan.belongs == ER_UNKNOWN) {
1408 parent_entity->request_scan.belongs = ER_FALSE;
1409 register_kicked_entity(parent_entity, 1 /* priority */);
1413 static void membership_parent_solve TAC_ARGS((struct membership *membership, enum eval_result how));
1416 membership_parent_solve(membership, how)
1417 struct membership *membership;
1418 enum eval_result how;
1420 enum eval_result negative = (how == ER_TRUE ? ER_FALSE : ER_TRUE);
1421 ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1423 check_request_scan_entity(parent_entity, 0);
1425 if (parent_entity->request_scan.belongs == negative)
1426 report(LOG_ERR, "INTERNAL: parent " PF_ENTITY "already negative to what says membership " PF_MEMBERSHIP "in membership_eval_immediate",
1427 PA_ENTITY(parent_entity), PA_MEMBERSHIP(membership));
1429 parent_entity->request_scan.belongs = how;
1430 register_kicked_entity(parent_entity, 1 /* priority */);
1432 membership_solved(membership);
1434 if (debug & DEBUG_CFGEVAL_FLAG)
1435 report(LOG_DEBUG, "membership_parent_solve: " PF_MEMBERSHIP " marked parent " PF_ENTITY,
1436 PA_MEMBERSHIP(membership), PA_ENTITY(parent_entity));
1439 static void membership_eval_immediate TAC_ARGS((struct membership *membership));
1442 membership_eval_immediate(membership)
1443 struct membership *membership;
1445 enum eval_result membership_valid;
1446 ENTITY *child_entity, *parent_entity;
1448 if (debug & DEBUG_CFGEVAL_FLAG)
1449 report(LOG_DEBUG, "membership_eval_immediate: " PF_MEMBERSHIP,
1450 PA_MEMBERSHIP(membership));
1452 check_eval_scan_membership(membership, 0);
1454 if (!membership->eval_scan.unsolved)
1456 parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1457 check_request_scan_entity(parent_entity, 0);
1458 if (parent_entity->request_scan.belongs != ER_UNKNOWN) /* why to solve this membership? */
1461 membership_valid = expr_eval_immediate(membership->when);
1463 child_entity = MEMBERSHIP_TO_CHILD_ENTITY( membership);
1464 check_request_scan_entity( child_entity, 0);
1466 #if 0 /* non-valid membership doesn't YET solve the parent! */
1467 if (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE) {
1468 membership_parent_solve(membership, ER_FALSE);
1473 if (child_entity->request_scan.belongs == ER_TRUE && membership_valid == ER_TRUE ) {
1474 membership_parent_solve(membership, ER_TRUE );
1478 if ( child_entity->request_scan.belongs == ER_UNKNOWN)
1479 register_kicked_entity( child_entity, 0 /* priority */);
1480 if (parent_entity->request_scan.belongs == ER_UNKNOWN)
1481 register_kicked_entity(parent_entity, 0 /* priority */);
1483 if (parent_entity->request_scan.belongs != ER_UNKNOWN
1484 || (child_entity->request_scan.belongs == ER_FALSE || membership_valid == ER_FALSE))
1485 membership_solved(membership);
1487 if (debug & DEBUG_CFGEVAL_FLAG)
1488 report(LOG_DEBUG, "membership_eval_immediate: done: " PF_MEMBERSHIP,
1489 PA_MEMBERSHIP(membership));
1492 static void entity_eval_immediate TAC_ARGS((ENTITY *entity));
1495 entity_eval_immediate(entity)
1498 struct tac_list_node *notified_expr_node;
1499 struct tac_list_node *child_membership_node;
1501 if (debug & DEBUG_CFGEVAL_FLAG)
1502 report(LOG_DEBUG, "entity_eval_immediate: " PF_ENTITY,
1505 check_eval_scan_entity(entity, 0);
1507 if (!request_scan_user_known) {
1508 #ifdef SCAN_PARANOIA
1509 if (entity->request_scan.belongs != ER_UNKNOWN)
1510 report(LOG_ERR, "INTERNAL: belonging known while still !request_scan_user_known for " PF_ENTITY " in entity_eval_immediate",
1516 if (entity->request_scan.belongs == ER_UNKNOWN) {
1517 if (entity->eval_scan.unsolved_to_child_membership_first) {
1518 struct membership *order_membership = entity->eval_scan.unsolved_to_child_membership_first;
1519 struct tac_list_node *next_membership_parent_node = tac_list_node_next(&order_membership->parent_node);
1521 membership_eval_immediate(order_membership);
1522 if (next_membership_parent_node)
1523 entity->eval_scan.unsolved_to_child_membership_first = PARENT_NODE_TO_MEMBERSHIP(next_membership_parent_node);
1525 entity->eval_scan.unsolved_to_child_membership_first = NULL;
1527 register_kicked_entity(entity, 0 /* priority */);
1529 if (debug & DEBUG_CFGEVAL_FLAG)
1530 report(LOG_DEBUG, "entity_eval_immediate: finishing as we ordered child membership: " PF_MEMBERSHIP,
1531 PA_MEMBERSHIP(order_membership));
1535 if (!entity->eval_scan.unsolved_to_child_membership_num)
1536 entity->request_scan.belongs = ER_FALSE;
1538 if (debug & DEBUG_CFGEVAL_FLAG)
1539 report(LOG_DEBUG, "entity_eval_immediate: finishing as unsolved child memberships still available and I'm still clueless");
1543 /* belonging is known here */
1545 /* recheck all memberships we may decide */
1547 child_membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1548 child_membership_node;
1549 child_membership_node = tac_list_node_next(child_membership_node)
1551 struct membership *child_membership = CHILD_NODE_TO_MEMBERSHIP(child_membership_node);
1553 membership_eval_immediate(child_membership);
1556 /* notify all exprs which are interested in us */
1557 while ((notified_expr_node = tac_list_first_node(&entity->eval_scan.notify_expr_list))) {
1558 tac_list_node_remove(notified_expr_node);
1559 tac_list_addtail(&eval_notified_expr_list, notified_expr_node);
1562 if (debug & DEBUG_CFGEVAL_FLAG)
1563 report(LOG_DEBUG, "entity_eval_immediate: done: " PF_ENTITY,
1568 enum eval_result expr_eval TAC_ARGS((struct expr *expr));
1574 if (debug & DEBUG_CFGEVAL_FLAG)
1575 report(LOG_DEBUG, "expr_eval: top level order for " PF_EXPR,
1582 if (expr_eval_immediate(expr) != ER_UNKNOWN)
1583 return (expr->request_scan.result);
1585 /* all 'solved' nodes MUST be removed BEFORE '*_immediate()' has been called,
1586 * otherwise we may have no longer valid node!
1589 struct tac_list_node *notified_expr_node, *kicked_entity_node;
1591 /* check it rather always, checking just on notifications looks too complex.
1593 if (expr->request_scan.result != ER_UNKNOWN) {
1594 if (debug & DEBUG_CFGEVAL_FLAG)
1595 report(LOG_DEBUG, "expr_eval: finishing as ordered " PF_EXPR " got known",
1597 return (expr->request_scan.result);
1600 #if 0 /* not needed as it is now always called after any destroy */
1601 expr_eval_notify_expr_flush_destroy_entity_list(); /* eval_destroy_entity_list */
1602 #endif /* not needed */
1604 if ((notified_expr_node = tac_list_first_node(&eval_notified_expr_list))) {
1605 struct expr *notified_expr = NOTIFY_EXPR_NODE_TO_EXPR(notified_expr_node);
1607 if (debug & DEBUG_CFGEVAL_FLAG)
1608 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_EXPR " from eval_NOTIFIED_expr_list",
1609 PA_EXPR(notified_expr));
1611 tac_list_node_remove(notified_expr_node);
1612 expr_eval_immediate(notified_expr);
1614 if (notified_expr->membership)
1615 membership_eval_immediate(notified_expr->membership);
1617 continue; /* shortcut */
1620 if ((kicked_entity_node = tac_list_first_node(&eval_kicked_entity_list))) {
1621 ENTITY *kicked_entity = PENDING_ENTITY_NODE_TO_ENTITY(kicked_entity_node);
1623 if (debug & DEBUG_CFGEVAL_FLAG)
1624 report(LOG_DEBUG, "expr_eval: PROCESSING " PF_ENTITY " from eval_KICKED_entity_list",
1625 PA_ENTITY(kicked_entity));
1627 tac_list_node_remove(kicked_entity_node);
1628 entity_eval_immediate(kicked_entity);
1629 continue; /* shortcut */
1632 break; /* nothing done yet, all lists are empty! */
1635 if (!expr->request_scan.loop_reported) {
1636 report(LOG_WARNING, "Unable to resolve expression from line %d, some looping occured", expr->line);
1637 expr->request_scan.loop_reported = 1;
1639 return (ER_UNKNOWN);
1643 void eval_force_belong_entity TAC_ARGS((ENTITY *entity));
1645 void eval_force_belong_entity(entity)
1648 if (debug & DEBUG_CFGEVAL_FLAG)
1649 report(LOG_DEBUG, "eval_force_belong_entity: " PF_ENTITY " (before check_scan " PF_ERESULT_ENTITY ")",
1650 PA_ENTITY(entity), PA_ERESULT_ENTITY(entity));
1652 check_request_scan_entity(entity, 0);
1654 if (entity->request_scan.belongs == ER_FALSE)
1655 report(LOG_ERR, "Dangerous force of TRUE to FALSE-determined entity in eval_force_belong_entity");
1657 entity->request_scan.belongs = ER_TRUE;
1660 void scan_init_entity TAC_ARGS((ENTITY *entity));
1663 scan_init_entity(entity)
1666 entity->request_scan.seq = request_scan_seq-1; /* invalidate */
1667 entity-> value_scan.seq = value_scan_seq-1; /* invalidate */
1668 entity-> eval_scan.seq = eval_scan_seq-1; /* invalidate */
1669 tac_list_init(&entity->eval_scan.notify_expr_list);
1670 tac_list_node_init(&entity->eval_scan.pending_entity_node);
1673 struct membership *enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child, struct expr *when));
1676 enlist_entity_direct(parent, child, when)
1681 struct membership *membership = (struct membership *) tac_malloc(sizeof(struct membership));
1683 tac_list_node_init(&membership->parent_node);
1684 tac_list_node_init(&membership->child_node);
1685 membership->request_scan.seq = request_scan_seq-1;
1686 tac_list_node_init(&membership->request_scan.virtual_membership_node);
1687 membership->eval_scan.seq = eval_scan_seq-1;
1689 tac_list_addtail(&parent->to_child_membership_list , &membership->parent_node);
1690 parent->to_child_membership_num++;
1691 tac_list_addtail(& child->to_parent_membership_list, &membership-> child_node);
1692 membership->when = when;
1693 if (expr_sink(membership->when, membership)) {
1694 unlink_membership(membership);
1695 free_membership(membership);
1699 if (debug & DEBUG_CFGEVAL_FLAG)
1700 report(LOG_DEBUG, "enlist_entity_direct: done: " PF_MEMBERSHIP,
1701 PA_MEMBERSHIP(membership));
1703 return (membership);
1706 struct membership *virtual_enlist_entity_direct TAC_ARGS((ENTITY *parent, ENTITY *child));
1709 virtual_enlist_entity_direct(parent, child)
1713 struct membership *membership;
1715 if (debug & DEBUG_CFGEVAL_FLAG)
1716 report(LOG_DEBUG, "virtual_enlist_entity_direct: the following enlist will be VIRTUAL...");
1718 membership = enlist_entity_direct(parent, child, NULL /* when */);
1722 check_request_scan_membership(membership, 0);
1723 tac_list_addtail(&request_virtual_membership_list, &membership->request_scan.virtual_membership_node);
1725 return (membership);
1728 /* returns given 'entity' or NULL if already visited */
1730 void (*value_scan_forward_seen_hook) TAC_ARGS((struct membership *membership));
1732 static ENTITY *value_scan_forward TAC_ARGS((struct membership *membership));
1735 value_scan_forward(membership)
1736 struct membership *membership;
1738 ENTITY *parent_entity;
1740 if (debug & DEBUG_CFGEVAL_FLAG)
1741 report(LOG_DEBUG, "value_scan_forward: from " PF_MEMBERSHIP " try forward...",
1742 PA_MEMBERSHIP(membership));
1744 parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1746 if (ER_TRUE != expr_eval(membership->when)) {
1747 if (debug & DEBUG_CFGEVAL_FLAG)
1748 report(LOG_DEBUG, "value_scan_forward: forward NOT successful due to failed 'when' evaluation.");
1751 check_value_scan_entity(parent_entity, 0);
1752 if (parent_entity->value_scan.seen) {
1753 if (debug & DEBUG_CFGEVAL_FLAG)
1754 report(LOG_DEBUG, "value_scan_forward: forward NOT successful as the parent " PF_ENTITY " was already seen this value scan.",
1755 PA_ENTITY(parent_entity));
1756 if (value_scan_forward_seen_hook)
1757 (*value_scan_forward_seen_hook)(membership);
1760 parent_entity->value_scan.seen = 1;
1761 parent_entity->value_scan.from = membership;
1763 if (debug & DEBUG_CFGEVAL_FLAG)
1764 report(LOG_DEBUG, "value_scan_forward: forward SUCCESSFUL to parent " PF_ENTITY,
1765 PA_ENTITY(parent_entity));
1766 return (parent_entity);
1769 struct membership *value_scan_backward TAC_ARGS((ENTITY *entity));
1772 value_scan_backward(entity)
1775 if (debug & DEBUG_CFGEVAL_FLAG)
1776 report(LOG_DEBUG, "value_scan_backward: from " PF_ENTITY " went back to " PF_MEMBERSHIP,
1777 PA_ENTITY(entity), PA_MEMBERSHIP(entity->value_scan.from));
1779 #ifdef SCAN_PARANOIA
1780 if (entity->value_scan.seq != value_scan_seq) {
1781 report(LOG_ERR, "entity value_scan NOT up-to-date in value_scan_backward");
1786 return (entity->value_scan.from);
1789 /* Scan the entity graph and return each node found.
1790 'when' conditions for graph connections are respected,
1791 looping is correctly prevented.
1794 enum value_scan_func_result value_scan_entity TAC_ARGS((ENTITY *entity, int recurse, value_scan_func_t func, void *func_data));
1796 enum value_scan_func_result
1797 value_scan_entity(entity, recurse, func, func_data)
1800 value_scan_func_t func;
1803 enum value_scan_func_result vsfr;
1804 struct tac_list_node *membership_node;
1806 if (debug & DEBUG_CFGEVAL_FLAG)
1807 report(LOG_DEBUG, "value_scan_entity: " PF_ENTITY ", recurse=%d",
1808 PA_ENTITY(entity), recurse);
1810 vsfr=(*func)(entity,func_data);
1812 if (debug & DEBUG_CFGEVAL_FLAG)
1813 report(LOG_DEBUG, "value_scan_entity: root func-> " PF_VSFR,
1816 if (vsfr != VSFR_CONTINUE) {
1817 if (debug & DEBUG_CFGEVAL_FLAG)
1818 report(LOG_DEBUG, "value_scan_entity: finishing as root func didn't return VSFR_CONTINUE");
1822 if (debug & DEBUG_CFGEVAL_FLAG)
1823 report(LOG_DEBUG, "value_scan_entity: finishing as recurse not ordered");
1827 value_scan_begin(entity);
1828 membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1829 if (!membership_node) {
1830 if (debug & DEBUG_CFGEVAL_FLAG)
1831 report(LOG_DEBUG, "value_scan_entity: finishing as no parent entities of root");
1832 return (VSFR_CONTINUE); /* no parent entities */
1836 struct membership *membership = CHILD_NODE_TO_MEMBERSHIP(membership_node);
1838 if (debug & DEBUG_CFGEVAL_FLAG)
1839 report(LOG_DEBUG, "value_scan_entity: trace loop start: " PF_MEMBERSHIP,
1840 PA_MEMBERSHIP(membership));
1842 entity = value_scan_forward(membership);
1844 if (debug & DEBUG_CFGEVAL_FLAG)
1845 report(LOG_DEBUG, "value_scan_entity: successful recurse to " PF_ENTITY,
1848 vsfr=(*func)(entity,func_data);
1850 if (debug & DEBUG_CFGEVAL_FLAG)
1851 report(LOG_DEBUG, "value_scan_entity: func(" PF_ENTITY ")-> " PF_VSFR,
1852 PA_ENTITY(entity), PA_VSFR(vsfr));
1854 if (vsfr == VSFR_FOUND) {
1855 if (debug & DEBUG_CFGEVAL_FLAG)
1856 report(LOG_DEBUG, "value_scan_entity: finishing as func returned VSFR_FOUND");
1859 if (vsfr == VSFR_CONTINUE)
1860 membership_node = tac_list_first_node(&entity->to_parent_membership_list);
1862 if (!entity || vsfr == VSFR_STOP) {
1863 ENTITY *parent_entity = MEMBERSHIP_TO_PARENT_ENTITY(membership);
1865 entity = MEMBERSHIP_TO_CHILD_ENTITY(membership); /* for retreat from the LAST membership */
1867 if (debug & DEBUG_CFGEVAL_FLAG)
1868 report(LOG_DEBUG, "value_scan_entity: unsuccessful recurse to " PF_ENTITY ", tracing back through child " PF_ENTITY,
1869 PA_ENTITY(parent_entity), PA_ENTITY(entity));
1871 membership_node = tac_list_node_next(&membership->child_node);
1874 while (!membership_node) {
1875 membership = value_scan_backward(entity);
1877 if (debug & DEBUG_CFGEVAL_FLAG)
1878 report(LOG_DEBUG, "value_scan_entity: finishing as all nodes were scanned");
1879 return (VSFR_CONTINUE); /* FINISH */
1882 entity = MEMBERSHIP_TO_CHILD_ENTITY(membership); /* for retreat from the LAST membership */
1884 if (debug & DEBUG_CFGEVAL_FLAG)
1885 report(LOG_DEBUG, "value_scan_entity: backward retreat ('next' chase) "
1886 "through " PF_MEMBERSHIP " to child " PF_ENTITY,
1887 PA_MEMBERSHIP(membership), PA_ENTITY(entity));
1889 membership_node = tac_list_node_next(&membership->child_node);