3 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 * Licensed under the Apache License, Version 2.0 (the License);
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
22 #include "utility/fw_assert.h"
23 #include "utility/sync_util.h"
24 #include "engine-controller/queuing_rule_spec.h"
25 #include "engine-controller/queuing_rule_spec_internal.h"
26 #include "engine-controller/task_spec_internal.h"
27 #include "engine-controller/task.h"
28 #include "engine-controller/task_message.h"
29 #include "engine-controller/internal.h"
32 #define EXPORT_API __attribute__ ((visibility("default")))
35 #ifndef SYNC_AGENT_LOG
37 #define LOG_TAG "AF_EC"
40 static ec_progress_blocking_entity_t *_queuing_rule_spec_get_progress_blocking_entity(sync_agent_ec_queuing_rule_spec_s * rule, sync_agent_ec_uint root_task_spec_id)
44 retvm_if(rule == NULL, NULL, "sync_agent_ec_queuing_rule_spec_s is NULL !!");
47 ec_progress_blocking_entity_t *entity = NULL;
48 for (iter = rule->progress_blocking_entity_list; iter != NULL; iter = g_slist_next(iter)) {
49 entity = (ec_progress_blocking_entity_t *) (iter->data);
50 if (entity->root_task_spec_id == root_task_spec_id) {
60 static sync_agent_ec_boolean _queuing_rule_spec_is_valid_child_path(sync_agent_ec_task_spec_s * root_task_spec, sync_agent_ec_uint child_depth, va_list ap)
64 retvm_if(root_task_spec == NULL, false, "sync_agent_ec_task_spec_s is NULL !!");
66 sync_agent_ec_uint i = 0;
67 sync_agent_ec_boolean is_dynamic = false;
68 sync_agent_ec_int dynamic_case = 0;
69 sync_agent_ec_int child_index = 0;
71 sync_agent_ec_task_spec_s *parent_task_spec = root_task_spec;
72 sync_agent_ec_boolean parent_is_dynamic = false;
73 sync_agent_ec_task_spec_s *child_task_spec = NULL;
75 for (i = 0; i < child_depth; i++) {
76 is_dynamic = va_arg(ap, sync_agent_ec_boolean);
77 dynamic_case = va_arg(ap, sync_agent_ec_int);
78 child_index = va_arg(ap, sync_agent_ec_int);
80 /* not container or dynamic container case */
81 if (ec_task_spec_is_simple(parent_task_spec)) {
85 /* check dynamic equality */
86 parent_is_dynamic = ec_task_spec_is_dynamic_container(parent_task_spec);
87 if ((is_dynamic && !parent_is_dynamic) || (!is_dynamic && parent_is_dynamic)) {
92 if (SYNC_AGENT_EC_OK != ec_task_spec_valididate_child_task_index_on_dynamic_case(dynamic_case, parent_task_spec, child_index)) {
95 child_task_spec = ec_task_spec_get_child_task_spec_on_dynamic_case(dynamic_case, parent_task_spec, child_index);
97 if (SYNC_AGENT_EC_OK != ec_task_spec_valididate_child_task_index(parent_task_spec, child_index)) {
100 child_task_spec = ec_task_spec_get_child_task_spec(parent_task_spec, child_index);
103 SYNC_AGENT_UTIL_ASSERT_CONDITION(child_task_spec != NULL, "valid child but can ec_task_spec_get_child_task_spec or ec_task_spec_get_child_task_spec_on_dynamic_case return NULL\n");
105 parent_task_spec = child_task_spec;
113 static void _queuing_rule_spec_free_queuing_rule_spec(sync_agent_ec_queuing_rule_spec_s * rule)
118 if (rule->name != NULL) {
122 if (rule->progress_blocking_entity_list != NULL) {
124 ec_progress_blocking_entity_t *entity = NULL;
125 for (iter = rule->progress_blocking_entity_list; iter != NULL; iter = g_slist_next(iter)) {
126 entity = (ec_progress_blocking_entity_t *) (iter->data);
127 ec_progress_blocking_entity_free(entity);
130 g_slist_free(rule->progress_blocking_entity_list);
133 if (rule->progress_blocking_queue != NULL) {
134 g_queue_free(rule->progress_blocking_queue);
143 /* implementation of queuing_rule_spec_internal.h */
145 ec_n_ary_tree_node_with_flag_t *ec_n_ary_tree_node_with_flag_new(sync_agent_ec_boolean blocking_flag, sync_agent_ec_uint tree_level, sync_agent_ec_boolean is_dynamic_child, sync_agent_ec_int dynamic_case, sync_agent_ec_uint child_index)
149 ec_n_ary_tree_node_with_flag_t *node = (ec_n_ary_tree_node_with_flag_t *) malloc(sizeof(ec_n_ary_tree_node_with_flag_t));
154 node->blocking_flag = blocking_flag;
156 node->tree_level = tree_level;
157 node->is_dynamic_child = is_dynamic_child;
158 node->dynamic_case = dynamic_case;
159 node->child_index = child_index;
161 node->parent_node = NULL;
162 node->first_child_node = NULL;
163 node->next_sibling_node = NULL;
164 node->prev_sibling_node = NULL;
171 ec_n_ary_tree_node_with_flag_free_1(node);
175 void ec_n_ary_tree_node_with_flag_free_1(ec_n_ary_tree_node_with_flag_t * node)
186 void ec_n_ary_tree_node_with_flag_free_subtree(ec_n_ary_tree_node_with_flag_t * node)
190 retm_if(node == NULL, "ec_n_ary_tree_node_with_flag_t is NULL !!");
192 if (node->parent_node != NULL) {
193 ec_n_ary_tree_node_with_flag_unlink_child_node(node->parent_node, node);
196 /* destroy all children without using recursive call */
197 ec_n_ary_tree_node_with_flag_t *current_node = node;
198 ec_n_ary_tree_node_with_flag_t *previous_node = NULL;
200 sync_agent_ec_boolean end_of_walk = false;
201 sync_agent_ec_boolean has_to_check_child = true;
202 while (!end_of_walk) {
203 previous_node = current_node;
204 if (has_to_check_child) {
205 if (current_node->first_child_node == NULL) {
206 if (current_node->next_sibling_node == NULL) {
207 current_node = current_node->parent_node;
208 has_to_check_child = false;
210 current_node = current_node->next_sibling_node;
211 has_to_check_child = true;
213 ec_n_ary_tree_node_with_flag_free_1(previous_node);
215 /* goto leaf node step by step */
216 current_node = current_node->first_child_node;
218 /* note that we do not free prev node in this case */
221 if (current_node->next_sibling_node == NULL) {
222 current_node = current_node->parent_node;
224 /* goto next sibling since all children of current node are freed */
225 current_node = current_node->next_sibling_node;
226 has_to_check_child = true;
228 ec_n_ary_tree_node_with_flag_free_1(previous_node);
231 if (current_node == NULL) {
239 sync_agent_ec_uint ec_n_ary_tree_node_with_flag_count_subtree_flag_on_number(ec_n_ary_tree_node_with_flag_t * node)
243 sync_agent_ec_uint count_flag_on = 0;
245 /* visit all children to count flag on number without using recursive call */
246 ec_n_ary_tree_node_with_flag_t *current_node = node;
247 ec_n_ary_tree_node_with_flag_t *previous_node = NULL;
249 sync_agent_ec_boolean end_of_walk = false;
250 sync_agent_ec_boolean has_to_check_child = true;
251 while (!end_of_walk) {
252 previous_node = current_node;
253 if (has_to_check_child) {
254 if (current_node->first_child_node == NULL) {
255 /* set next current node */
256 if (current_node->next_sibling_node == NULL) {
257 current_node = current_node->parent_node;
258 has_to_check_child = false;
260 current_node = current_node->next_sibling_node;
261 has_to_check_child = true;
264 if (ec_n_ary_tree_node_with_flag_is_blocking_flag_on(previous_node)) {
268 /* goto leaf node step by step */
269 current_node = current_node->first_child_node;
271 /* note that we do not free prev node in this case */
274 if (current_node->next_sibling_node == NULL) {
275 current_node = current_node->parent_node;
277 /* goto next sibling since all children of current node are freed */
278 current_node = current_node->next_sibling_node;
279 has_to_check_child = true;
282 if (ec_n_ary_tree_node_with_flag_is_blocking_flag_on(previous_node)) {
287 if (current_node == node->parent_node || current_node == node->next_sibling_node) {
294 return count_flag_on;
297 void ec_n_ary_tree_node_with_flag_set_blocking_flag_on(ec_n_ary_tree_node_with_flag_t * node)
301 retm_if(node == NULL, "ec_n_ary_tree_node_with_flag_t is NULL !!");
303 node->blocking_flag = true;
308 sync_agent_ec_boolean ec_n_ary_tree_node_with_flag_is_blocking_flag_on(ec_n_ary_tree_node_with_flag_t * node)
314 return node->blocking_flag;
317 sync_agent_ec_boolean ec_n_ary_tree_node_with_flag_has_same_content_without_blocking_flag(ec_n_ary_tree_node_with_flag_t * node, sync_agent_ec_uint tree_level, sync_agent_ec_boolean is_dynamic_child, sync_agent_ec_int dynamic_case,
318 sync_agent_ec_uint child_index)
322 if (node->tree_level == tree_level && node->is_dynamic_child == is_dynamic_child) {
323 if (is_dynamic_child) {
324 if (node->dynamic_case == dynamic_case && node->child_index == child_index) {
329 if (node->child_index == child_index) {
341 ec_n_ary_tree_node_with_flag_t *ec_n_ary_tree_node_with_flag_add_child_node(ec_n_ary_tree_node_with_flag_t * parent_node, sync_agent_ec_boolean blocking_flag, sync_agent_ec_boolean is_dynamic_child, sync_agent_ec_int dynamic_case,
342 sync_agent_ec_uint child_index)
346 retvm_if(parent_node == NULL, NULL, "ec_n_ary_tree_node_with_flag_t is NULL !!");
348 ec_n_ary_tree_node_with_flag_t *child_node = ec_n_ary_tree_node_with_flag_new(blocking_flag, parent_node->tree_level + 1,
349 is_dynamic_child, dynamic_case, child_index);
350 if (child_node == NULL) {
354 ec_n_ary_tree_node_with_flag_link_child_node(parent_node, child_node);
361 void ec_n_ary_tree_node_with_flag_link_child_node(ec_n_ary_tree_node_with_flag_t * parent_node, ec_n_ary_tree_node_with_flag_t * child_node)
365 retm_if(parent_node == NULL, "ec_n_ary_tree_node_with_flag_t is NULL !!");
368 child_node->parent_node = parent_node;
371 if (parent_node->first_child_node != NULL) {
372 parent_node->first_child_node->prev_sibling_node = child_node;
374 child_node->next_sibling_node = parent_node->first_child_node;
375 parent_node->first_child_node = child_node;
380 void ec_n_ary_tree_node_with_flag_unlink_child_node(ec_n_ary_tree_node_with_flag_t * parent_node, ec_n_ary_tree_node_with_flag_t * child_node)
384 if (parent_node == NULL) {
388 if (parent_node->first_child_node == child_node) {
389 parent_node->first_child_node = child_node->next_sibling_node;
392 child_node->parent_node = NULL;
394 /* unlink sibling list */
395 if (child_node->prev_sibling_node != NULL) {
396 child_node->prev_sibling_node->next_sibling_node = child_node->next_sibling_node;
398 if (child_node->next_sibling_node != NULL) {
399 child_node->next_sibling_node->prev_sibling_node = child_node->prev_sibling_node;
405 ec_n_ary_tree_node_with_flag_t *ec_n_ary_tree_node_with_flag_get_child_node(ec_n_ary_tree_node_with_flag_t * parent_node, sync_agent_ec_boolean is_dynamic_child, sync_agent_ec_int dynamic_case, sync_agent_ec_uint child_index)
409 retvm_if(parent_node == NULL, NULL, "ec_n_ary_tree_node_with_flag_t is NULL !!");
411 ec_n_ary_tree_node_with_flag_t *child_node = NULL;
412 for (child_node = parent_node->first_child_node; child_node != NULL; child_node = child_node->next_sibling_node) {
413 if (ec_n_ary_tree_node_with_flag_has_same_content_without_blocking_flag(child_node, parent_node->tree_level + 1, is_dynamic_child, dynamic_case, child_index)) {
423 ec_progress_blocking_element_set_t *ec_progress_blocking_element_set_new()
427 ec_progress_blocking_element_set_t *set = (ec_progress_blocking_element_set_t *) calloc(1, sizeof(ec_progress_blocking_element_set_t));
432 set->progress_blocking_element_cnt = 0;
433 set->n_ary_tree_with_flag = ec_n_ary_tree_node_with_flag_new(false, 0, 0, 0, 0); /* set root node */
434 if (set->n_ary_tree_with_flag == NULL) {
443 ec_progress_blocking_element_set_free(set);
447 void ec_progress_blocking_element_set_free(ec_progress_blocking_element_set_t * set)
452 if (set->n_ary_tree_with_flag != NULL) {
453 ec_n_ary_tree_node_with_flag_free_subtree(set->n_ary_tree_with_flag);
454 set->n_ary_tree_with_flag = NULL;
463 sync_agent_ec_error_e ec_progress_blocking_element_add(ec_progress_blocking_element_set_t * set, sync_agent_ec_uint depth, va_list ap)
467 retvm_if(set == NULL, SYNC_AGENT_EC_UNKNOWN_ERROR, "ec_progress_blocking_element_set_t is NULL !!");
469 sync_agent_ec_error_e ec_error = SYNC_AGENT_EC_OK;
471 ec_n_ary_tree_node_with_flag_t *root_node = set->n_ary_tree_with_flag; /* note that root_node != NULL */
472 ec_n_ary_tree_node_with_flag_t *last_exist_parent_node = NULL;
473 ec_n_ary_tree_node_with_flag_t *first_alloc_node = NULL;
474 ec_n_ary_tree_node_with_flag_t *parent_node = NULL;
475 ec_n_ary_tree_node_with_flag_t *child_node = NULL;
477 sync_agent_ec_boolean is_dynamic_child = false;
478 sync_agent_ec_int dynamic_case = 0;
479 sync_agent_ec_uint child_index = 0;
481 sync_agent_ec_uint i = 0;
484 if (!(root_node->blocking_flag)) {
485 (set->progress_blocking_element_cnt)++;
486 ec_n_ary_tree_node_with_flag_set_blocking_flag_on(root_node);
492 parent_node = root_node;
493 for (i = 1; i <= depth; i++) {
494 is_dynamic_child = va_arg(ap, sync_agent_ec_boolean);
495 dynamic_case = va_arg(ap, sync_agent_ec_int);
496 child_index = va_arg(ap, sync_agent_ec_int);
498 child_node = ec_n_ary_tree_node_with_flag_get_child_node(parent_node, is_dynamic_child, dynamic_case, child_index);
500 if (child_node == NULL) {
501 last_exist_parent_node = parent_node;
502 first_alloc_node = ec_n_ary_tree_node_with_flag_add_child_node(parent_node, i == depth, is_dynamic_child, dynamic_case, child_index);
503 if (first_alloc_node == NULL) {
504 ec_error = SYNC_AGENT_EC_OUT_OF_MEMORY;
509 (set->progress_blocking_element_cnt)++;
513 parent_node = first_alloc_node;
516 parent_node = child_node;
519 if (child_node != NULL) {
520 /* already exist child node */
521 if (!(child_node->blocking_flag)) {
522 ec_n_ary_tree_node_with_flag_set_blocking_flag_on(child_node);
523 (set->progress_blocking_element_cnt)++;
528 for (i++; i <= depth; i++) {
529 is_dynamic_child = va_arg(ap, sync_agent_ec_boolean);
530 dynamic_case = va_arg(ap, sync_agent_ec_int);
531 child_index = va_arg(ap, sync_agent_ec_int);
533 child_node = ec_n_ary_tree_node_with_flag_add_child_node(parent_node, (i == depth), is_dynamic_child, dynamic_case, child_index);
534 if (child_node == NULL) {
538 parent_node = child_node;
540 (set->progress_blocking_element_cnt)++;
544 if (last_exist_parent_node == NULL) { /* when set->n_ary_tree_with_flag == NULL */
545 set->n_ary_tree_with_flag = first_alloc_node;
553 if (first_alloc_node != NULL) {
554 ec_n_ary_tree_node_with_flag_free_subtree(first_alloc_node);
559 ec_progress_blocking_entity_t *ec_progress_blocking_entity_new(sync_agent_ec_uint root_task_spec_id, sync_agent_ec_queuing_rule_spec_s * queuing_rule_spec)
563 ec_progress_blocking_entity_t *entity = (ec_progress_blocking_entity_t *) calloc(1, sizeof(ec_progress_blocking_entity_t));
564 if (entity == NULL) {
568 entity->ref_count = 1;
569 entity->root_task_spec_id = root_task_spec_id;
570 entity->queuing_rule_spec = ec_ref_queuing_rule_spec(queuing_rule_spec);
571 entity->element_set = ec_progress_blocking_element_set_new();
572 if (entity->element_set == NULL) {
581 ec_progress_blocking_entity_free(entity);
585 void ec_progress_blocking_entity_free(ec_progress_blocking_entity_t * entity)
589 if (entity != NULL) {
590 if (entity->element_set != NULL) {
591 ec_progress_blocking_element_set_free(entity->element_set);
593 if (entity->queuing_rule_spec != NULL) {
594 sync_agent_unref_queuing_rule_spec(entity->queuing_rule_spec);
602 ec_progress_blocking_entity_t *ec_progress_blocking_entity_ref(ec_progress_blocking_entity_t * entity)
606 if (entity == NULL) {
610 g_atomic_int_inc(&(entity->ref_count));
617 void ec_progress_blocking_entity_unref(ec_progress_blocking_entity_t * entity)
621 if (entity == NULL) {
625 if (g_atomic_int_dec_and_test(&(entity->ref_count))) {
626 ec_progress_blocking_entity_free(entity);
632 /* implementation of queuing_rule_spec.h */
634 EXPORT_API sync_agent_ec_queuing_rule_spec_s *sync_agent_create_queuing_rule_spec_outline(sync_agent_ec_char * queuing_rule_name)
638 retvm_if(queuing_rule_name == NULL, NULL, "sync_agent_ec_char is NULL !!");
640 sync_agent_ec_queuing_rule_spec_s *rule = (sync_agent_ec_queuing_rule_spec_s *) calloc(1, sizeof(sync_agent_ec_queuing_rule_spec_s));
646 rule->name = strdup(queuing_rule_name);
647 if (rule->name == NULL) {
651 rule->total_progress_blocking_element_cnt = 0;
652 rule->progress_blocking_entity_list = NULL;
654 rule->progress_blocking_queue = g_queue_new();
655 if (rule->progress_blocking_queue == NULL) {
664 _queuing_rule_spec_free_queuing_rule_spec(rule);
668 /* TODO : better performance expected if validation & check duplication & add new queuing element are done by one scanning */
669 EXPORT_API sync_agent_ec_error_e sync_agent_add_progress_blocking_element(sync_agent_ec_queuing_rule_spec_s * rule, sync_agent_ec_uint root_task_spec_id, sync_agent_ec_task_spec_s * root_task_spec, sync_agent_ec_uint child_depth, ...)
673 /* sync_agent_ec_boolean is_dynamic, sync_agent_ec_int dynamic_case, sync_agent_ec_int child_index */
674 sync_agent_ec_error_e ec_error = SYNC_AGENT_EC_OK;
675 sync_agent_ec_boolean new_entity = false;
676 ec_progress_blocking_entity_t *entity = NULL;
679 va_start(ap, child_depth);
681 /* check validity of child path */
682 if (!_queuing_rule_spec_is_valid_child_path(root_task_spec, child_depth, ap)) {
683 ec_error = SYNC_AGENT_EC_INVALID_CHILD_PATH;
690 va_start(ap, child_depth);
692 /* find progress blocking entity */
693 entity = _queuing_rule_spec_get_progress_blocking_entity(rule, root_task_spec_id);
694 if (entity == NULL) {
695 entity = ec_progress_blocking_entity_new(root_task_spec_id, rule);
696 if (entity == NULL) {
697 ec_error = SYNC_AGENT_EC_OUT_OF_MEMORY;
705 /* add_child_path to blocking entity */
706 ec_error = ec_progress_blocking_element_add(entity->element_set, child_depth, ap);
707 if (ec_error != SYNC_AGENT_EC_OK) {
715 rule->total_progress_blocking_element_cnt++;
716 rule->progress_blocking_entity_list = g_slist_prepend(rule->progress_blocking_entity_list, entity);
722 ec_progress_blocking_entity_free(entity);
732 ec_progress_blocking_entity_unref(entity);
738 sync_agent_ec_queuing_rule_spec_s *ec_ref_queuing_rule_spec(sync_agent_ec_queuing_rule_spec_s * rule)
742 SYNC_AGENT_UTIL_ASSERT_CONDITION(rule != NULL, "error. rule == NULL\n");
744 g_atomic_int_inc(&(rule->ref_count));
751 EXPORT_API void sync_agent_unref_queuing_rule_spec(sync_agent_ec_queuing_rule_spec_s * rule)
759 if (g_atomic_int_get(&(rule->ref_count)) <= 0) {
760 _DEBUG_ERROR("ref count <= 0\n");
763 if (g_atomic_int_dec_and_test(&(rule->ref_count))) {
764 _queuing_rule_spec_free_queuing_rule_spec(rule);