[Internal: merge sync-agent]
[platform/core/system/sync-agent.git] / src / framework / engine-controller / queuing_rule_spec.c
1 /*
2  * sync-agent
3  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4  *
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
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 #include <stdlib.h>
19 #include <stdarg.h>
20 #include <string.h>
21 #include <glib.h>
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"
30
31 #ifndef EXPORT_API
32 #define EXPORT_API __attribute__ ((visibility("default")))
33 #endif
34
35 #ifndef SYNC_AGENT_LOG
36 #undef LOG_TAG
37 #define LOG_TAG "AF_EC"
38 #endif
39
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)
41 {
42         _INNER_FUNC_ENTER;
43
44         retvm_if(rule == NULL, NULL, "sync_agent_ec_queuing_rule_spec_s is NULL !!");
45
46         GSList *iter = 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) {
51                         return entity;
52                 }
53         }
54
55         _INNER_FUNC_EXIT;
56
57         return NULL;
58 }
59
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)
61 {
62         _INNER_FUNC_ENTER;
63
64         retvm_if(root_task_spec == NULL, false, "sync_agent_ec_task_spec_s is NULL !!");
65
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;
70
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;
74
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);
79
80                 /* not container or dynamic container case */
81                 if (ec_task_spec_is_simple(parent_task_spec)) {
82                         return false;
83                 }
84
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)) {
88                         return false;
89                 }
90
91                 if (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)) {
93                                 return false;
94                         }
95                         child_task_spec = ec_task_spec_get_child_task_spec_on_dynamic_case(dynamic_case, parent_task_spec, child_index);
96                 } else {
97                         if (SYNC_AGENT_EC_OK != ec_task_spec_valididate_child_task_index(parent_task_spec, child_index)) {
98                                 return false;
99                         }
100                         child_task_spec = ec_task_spec_get_child_task_spec(parent_task_spec, child_index);
101                 }
102
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");
104
105                 parent_task_spec = child_task_spec;
106         }
107
108         _INNER_FUNC_EXIT;
109
110         return true;
111 }
112
113 static void _queuing_rule_spec_free_queuing_rule_spec(sync_agent_ec_queuing_rule_spec_s * rule)
114 {
115         _INNER_FUNC_ENTER;
116
117         if (rule != NULL) {
118                 if (rule->name != NULL) {
119                         free(rule->name);
120                 }
121
122                 if (rule->progress_blocking_entity_list != NULL) {
123                         GSList *iter = 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);
128                         }
129
130                         g_slist_free(rule->progress_blocking_entity_list);
131                 }
132
133                 if (rule->progress_blocking_queue != NULL) {
134                         g_queue_free(rule->progress_blocking_queue);
135                 }
136
137                 free(rule);
138         }
139
140         _INNER_FUNC_EXIT;
141 }
142
143 /* implementation of queuing_rule_spec_internal.h */
144
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)
146 {
147         _EXTERN_FUNC_ENTER;
148
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));
150         if (node == NULL) {
151                 goto error_part;
152         }
153
154         node->blocking_flag = blocking_flag;
155
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;
160
161         node->parent_node = NULL;
162         node->first_child_node = NULL;
163         node->next_sibling_node = NULL;
164         node->prev_sibling_node = NULL;
165
166         _EXTERN_FUNC_EXIT;
167
168         return node;
169
170  error_part:
171         ec_n_ary_tree_node_with_flag_free_1(node);
172         return NULL;
173 }
174
175 void ec_n_ary_tree_node_with_flag_free_1(ec_n_ary_tree_node_with_flag_t * node)
176 {
177         _EXTERN_FUNC_ENTER;
178
179         if (node != NULL) {
180                 free(node);
181         }
182
183         _EXTERN_FUNC_EXIT;
184 }
185
186 void ec_n_ary_tree_node_with_flag_free_subtree(ec_n_ary_tree_node_with_flag_t * node)
187 {
188         _EXTERN_FUNC_ENTER;
189
190         retm_if(node == NULL, "ec_n_ary_tree_node_with_flag_t is NULL !!");
191
192         if (node->parent_node != NULL) {
193                 ec_n_ary_tree_node_with_flag_unlink_child_node(node->parent_node, node);
194         }
195
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;
199
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;
209                                 } else {
210                                         current_node = current_node->next_sibling_node;
211                                         has_to_check_child = true;
212                                 }
213                                 ec_n_ary_tree_node_with_flag_free_1(previous_node);
214                         } else {
215                                 /* goto leaf node step by step */
216                                 current_node = current_node->first_child_node;
217
218                                 /* note that we do not free prev node in this case */
219                         }
220                 } else {
221                         if (current_node->next_sibling_node == NULL) {
222                                 current_node = current_node->parent_node;
223                         } else {
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;
227                         }
228                         ec_n_ary_tree_node_with_flag_free_1(previous_node);
229                 }
230
231                 if (current_node == NULL) {
232                         end_of_walk = true;
233                 }
234         }
235
236         _EXTERN_FUNC_EXIT;
237 }
238
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)
240 {
241         _EXTERN_FUNC_ENTER;
242
243         sync_agent_ec_uint count_flag_on = 0;
244
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;
248
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;
259                                 } else {
260                                         current_node = current_node->next_sibling_node;
261                                         has_to_check_child = true;
262                                 }
263
264                                 if (ec_n_ary_tree_node_with_flag_is_blocking_flag_on(previous_node)) {
265                                         count_flag_on++;
266                                 }
267                         } else {
268                                 /* goto leaf node step by step */
269                                 current_node = current_node->first_child_node;
270
271                                 /* note that we do not free prev node in this case */
272                         }
273                 } else {
274                         if (current_node->next_sibling_node == NULL) {
275                                 current_node = current_node->parent_node;
276                         } else {
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;
280                         }
281
282                         if (ec_n_ary_tree_node_with_flag_is_blocking_flag_on(previous_node)) {
283                                 count_flag_on++;
284                         }
285                 }
286
287                 if (current_node == node->parent_node || current_node == node->next_sibling_node) {
288                         end_of_walk = true;
289                 }
290         }
291
292         _EXTERN_FUNC_EXIT;
293
294         return count_flag_on;
295 }
296
297 void ec_n_ary_tree_node_with_flag_set_blocking_flag_on(ec_n_ary_tree_node_with_flag_t * node)
298 {
299         _EXTERN_FUNC_ENTER;
300
301         retm_if(node == NULL, "ec_n_ary_tree_node_with_flag_t is NULL !!");
302
303         node->blocking_flag = true;
304
305         _EXTERN_FUNC_EXIT;
306 }
307
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)
309 {
310         _EXTERN_FUNC_ENTER;
311
312         _EXTERN_FUNC_EXIT;
313
314         return node->blocking_flag;
315 }
316
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)
319 {
320         _EXTERN_FUNC_ENTER;
321
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) {
325                                 _EXTERN_FUNC_EXIT;
326                                 return true;
327                         }
328                 } else {
329                         if (node->child_index == child_index) {
330                                 _EXTERN_FUNC_EXIT;
331                                 return true;
332                         }
333                 }
334         }
335
336         _EXTERN_FUNC_EXIT;
337
338         return false;
339 }
340
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)
343 {
344         _EXTERN_FUNC_ENTER;
345
346         retvm_if(parent_node == NULL, NULL, "ec_n_ary_tree_node_with_flag_t is NULL !!");
347
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) {
351                 return NULL;
352         }
353
354         ec_n_ary_tree_node_with_flag_link_child_node(parent_node, child_node);
355
356         _EXTERN_FUNC_EXIT;
357
358         return child_node;
359 }
360
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)
362 {
363         _EXTERN_FUNC_ENTER;
364
365         retm_if(parent_node == NULL, "ec_n_ary_tree_node_with_flag_t is NULL !!");
366
367         /* set parent */
368         child_node->parent_node = parent_node;
369
370         /* set child */
371         if (parent_node->first_child_node != NULL) {
372                 parent_node->first_child_node->prev_sibling_node = child_node;
373         }
374         child_node->next_sibling_node = parent_node->first_child_node;
375         parent_node->first_child_node = child_node;
376
377         _EXTERN_FUNC_EXIT;
378 }
379
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)
381 {
382         _EXTERN_FUNC_ENTER;
383
384         if (parent_node == NULL) {
385                 return;
386         }
387
388         if (parent_node->first_child_node == child_node) {
389                 parent_node->first_child_node = child_node->next_sibling_node;
390         }
391
392         child_node->parent_node = NULL;
393
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;
397         }
398         if (child_node->next_sibling_node != NULL) {
399                 child_node->next_sibling_node->prev_sibling_node = child_node->prev_sibling_node;
400         }
401
402         _EXTERN_FUNC_EXIT;
403 }
404
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)
406 {
407         _EXTERN_FUNC_ENTER;
408
409         retvm_if(parent_node == NULL, NULL, "ec_n_ary_tree_node_with_flag_t is NULL !!");
410
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)) {
414                         break;
415                 }
416         }
417
418         _EXTERN_FUNC_EXIT;
419
420         return child_node;
421 }
422
423 ec_progress_blocking_element_set_t *ec_progress_blocking_element_set_new()
424 {
425         _EXTERN_FUNC_ENTER;
426
427         ec_progress_blocking_element_set_t *set = (ec_progress_blocking_element_set_t *) calloc(1, sizeof(ec_progress_blocking_element_set_t));
428         if (set == NULL) {
429                 goto error_part;
430         }
431
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) {
435                 goto error_part;
436         }
437
438         _EXTERN_FUNC_EXIT;
439
440         return set;
441
442  error_part:
443         ec_progress_blocking_element_set_free(set);
444         return NULL;
445 }
446
447 void ec_progress_blocking_element_set_free(ec_progress_blocking_element_set_t * set)
448 {
449         _EXTERN_FUNC_ENTER;
450
451         if (set != NULL) {
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;
455                 }
456
457                 free(set);
458         }
459
460         _EXTERN_FUNC_EXIT;
461 }
462
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)
464 {
465         _EXTERN_FUNC_ENTER;
466
467         retvm_if(set == NULL, SYNC_AGENT_EC_UNKNOWN_ERROR, "ec_progress_blocking_element_set_t is NULL !!");
468
469         sync_agent_ec_error_e ec_error = SYNC_AGENT_EC_OK;
470
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;
476
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;
480
481         sync_agent_ec_uint i = 0;
482
483         if (depth == 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);
487                 }
488
489                 return ec_error;
490         }
491
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);
497
498                 child_node = ec_n_ary_tree_node_with_flag_get_child_node(parent_node, is_dynamic_child, dynamic_case, child_index);
499
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;
505                                 goto error_part;
506                         }
507
508                         if (i == depth) {
509                                 (set->progress_blocking_element_cnt)++;
510                                 goto return_part;
511                         }
512
513                         parent_node = first_alloc_node;
514                         break;
515                 }
516                 parent_node = child_node;
517         }
518
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)++;
524                 }
525                 goto return_part;
526         } else {
527                 /* add child node */
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);
532
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) {
535                                 goto error_part;
536                         }
537
538                         parent_node = child_node;
539                 }
540                 (set->progress_blocking_element_cnt)++;
541         }
542
543  return_part:
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;
546         }
547
548         _EXTERN_FUNC_EXIT;
549
550         return ec_error;
551
552  error_part:
553         if (first_alloc_node != NULL) {
554                 ec_n_ary_tree_node_with_flag_free_subtree(first_alloc_node);
555         }
556         return ec_error;
557 }
558
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)
560 {
561         _EXTERN_FUNC_ENTER;
562
563         ec_progress_blocking_entity_t *entity = (ec_progress_blocking_entity_t *) calloc(1, sizeof(ec_progress_blocking_entity_t));
564         if (entity == NULL) {
565                 goto error_part;
566         }
567
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) {
573                 goto error_part;
574         }
575
576         _EXTERN_FUNC_EXIT;
577
578         return entity;
579
580  error_part:
581         ec_progress_blocking_entity_free(entity);
582         return NULL;
583 }
584
585 void ec_progress_blocking_entity_free(ec_progress_blocking_entity_t * entity)
586 {
587         _EXTERN_FUNC_ENTER;
588
589         if (entity != NULL) {
590                 if (entity->element_set != NULL) {
591                         ec_progress_blocking_element_set_free(entity->element_set);
592                 }
593                 if (entity->queuing_rule_spec != NULL) {
594                         sync_agent_unref_queuing_rule_spec(entity->queuing_rule_spec);
595                 }
596                 free(entity);
597         }
598
599         _EXTERN_FUNC_EXIT;
600 }
601
602 ec_progress_blocking_entity_t *ec_progress_blocking_entity_ref(ec_progress_blocking_entity_t * entity)
603 {
604         _EXTERN_FUNC_ENTER;
605
606         if (entity == NULL) {
607                 return NULL;
608         }
609
610         g_atomic_int_inc(&(entity->ref_count));
611
612         _EXTERN_FUNC_EXIT;
613
614         return entity;
615 }
616
617 void ec_progress_blocking_entity_unref(ec_progress_blocking_entity_t * entity)
618 {
619         _EXTERN_FUNC_ENTER;
620
621         if (entity == NULL) {
622                 return;
623         }
624
625         if (g_atomic_int_dec_and_test(&(entity->ref_count))) {
626                 ec_progress_blocking_entity_free(entity);
627         }
628
629         _EXTERN_FUNC_EXIT;
630 }
631
632 /* implementation of queuing_rule_spec.h */
633
634 EXPORT_API sync_agent_ec_queuing_rule_spec_s *sync_agent_create_queuing_rule_spec_outline(sync_agent_ec_char * queuing_rule_name)
635 {
636         _EXTERN_FUNC_ENTER;
637
638         retvm_if(queuing_rule_name == NULL, NULL, "sync_agent_ec_char is NULL !!");
639
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));
641         if (rule == NULL) {
642                 goto error_part;
643         }
644
645         rule->ref_count = 1;
646         rule->name = strdup(queuing_rule_name);
647         if (rule->name == NULL) {
648                 goto error_part;
649         }
650
651         rule->total_progress_blocking_element_cnt = 0;
652         rule->progress_blocking_entity_list = NULL;
653
654         rule->progress_blocking_queue = g_queue_new();
655         if (rule->progress_blocking_queue == NULL) {
656                 goto error_part;
657         }
658
659         _EXTERN_FUNC_EXIT;
660
661         return rule;
662
663  error_part:
664         _queuing_rule_spec_free_queuing_rule_spec(rule);
665         return NULL;
666 }
667
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, ...)
670 {
671         _EXTERN_FUNC_ENTER;
672
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;
677
678         va_list ap;
679         va_start(ap, child_depth);
680
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;
684                 va_end(ap);
685
686                 goto return_part;
687         }
688
689         va_end(ap);
690         va_start(ap, child_depth);
691
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;
698                         va_end(ap);
699                         goto return_part;
700                 } else {
701                         new_entity = true;
702                 }
703         }
704
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) {
708                 va_end(ap);
709                 goto return_part;
710         }
711
712         va_end(ap);
713
714         if (new_entity) {
715                 rule->total_progress_blocking_element_cnt++;
716                 rule->progress_blocking_entity_list = g_slist_prepend(rule->progress_blocking_entity_list, entity);
717         }
718
719  return_part:
720         if (new_entity) {
721                 if(entity != NULL) {
722                         ec_progress_blocking_entity_free(entity);
723                 }
724         }
725
726         _EXTERN_FUNC_EXIT;
727         return ec_error;
728
729 /*
730 error_part:
731         if (new_entity) {
732                 ec_progress_blocking_entity_unref(entity);
733         }
734         return ec_error;
735 */
736 }
737
738 sync_agent_ec_queuing_rule_spec_s *ec_ref_queuing_rule_spec(sync_agent_ec_queuing_rule_spec_s * rule)
739 {
740         _EXTERN_FUNC_ENTER;
741
742         SYNC_AGENT_UTIL_ASSERT_CONDITION(rule != NULL, "error. rule == NULL\n");
743
744         g_atomic_int_inc(&(rule->ref_count));
745
746         _EXTERN_FUNC_EXIT;
747
748         return rule;
749 }
750
751 EXPORT_API void sync_agent_unref_queuing_rule_spec(sync_agent_ec_queuing_rule_spec_s * rule)
752 {
753         _EXTERN_FUNC_ENTER;
754
755         if (rule == NULL) {
756                 return;
757         }
758
759         if (g_atomic_int_get(&(rule->ref_count)) <= 0) {
760                 _DEBUG_ERROR("ref count <= 0\n");
761         }
762
763         if (g_atomic_int_dec_and_test(&(rule->ref_count))) {
764                 _queuing_rule_spec_free_queuing_rule_spec(rule);
765         }
766
767         _EXTERN_FUNC_EXIT;
768 }