1 /* Copyright (c) 2011-2013 Da SimGrid Team. All rights reserved. */
3 /* This program is free software; you can redistribute it and/or modify it
4 * under the terms of the license (GNU LGPL) which comes with this package. */
6 #include "mc_private.h"
10 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_liveness, mc,
11 "Logging specific to algorithms for liveness properties verification");
13 /********* Global variables *********/
15 xbt_dynar_t acceptance_pairs;
16 xbt_dynar_t visited_pairs;
17 xbt_dynar_t successors;
20 /********* Static functions *********/
22 static int is_reached_acceptance_pair(xbt_automaton_state_t st){
24 int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
28 mc_acceptance_pair_t new_pair = NULL;
29 new_pair = xbt_new0(s_mc_acceptance_pair_t, 1);
30 new_pair->num = xbt_dynar_length(acceptance_pairs) + 1;
31 new_pair->automaton_state = st;
32 new_pair->prop_ato = xbt_dynar_new(sizeof(int), NULL);
33 new_pair->system_state = MC_take_snapshot();
35 /* Get values of propositional symbols */
38 unsigned int cursor = 0;
39 xbt_automaton_propositional_symbol_t ps = NULL;
40 xbt_dynar_foreach(_mc_property_automaton->propositional_symbols, cursor, ps){
41 f = (int_f_void_t)ps->function;
43 xbt_dynar_push_as(new_pair->prop_ato, int, res);
48 if(xbt_dynar_is_empty(acceptance_pairs)){
51 /* New acceptance pair */
52 xbt_dynar_push(acceptance_pairs, &new_pair);
65 mc_acceptance_pair_t pair_test = NULL;
67 xbt_dynar_foreach(acceptance_pairs, cursor, pair_test){
68 if(XBT_LOG_ISENABLED(mc_liveness, xbt_log_priority_debug))
69 XBT_DEBUG("****** Pair reached #%d ******", pair_test->num);
70 if(xbt_automaton_state_compare(pair_test->automaton_state, st) == 0){
71 if(xbt_automaton_propositional_symbols_compare_value(pair_test->prop_ato, new_pair->prop_ato) == 0){
72 if(snapshot_compare(new_pair->system_state, pair_test->system_state) == 0){
82 XBT_DEBUG("Different values of propositional symbols");
85 XBT_DEBUG("Different automaton state");
89 /* New acceptance pair */
90 xbt_dynar_push(acceptance_pairs, &new_pair);
105 static void set_acceptance_pair_reached(xbt_automaton_state_t st){
107 int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
111 mc_acceptance_pair_t pair = NULL;
112 pair = xbt_new0(s_mc_acceptance_pair_t, 1);
113 pair->num = xbt_dynar_length(acceptance_pairs) + 1;
114 pair->automaton_state = st;
115 pair->prop_ato = xbt_dynar_new(sizeof(int), NULL);
116 pair->system_state = MC_take_snapshot();
118 /* Get values of propositional symbols */
119 unsigned int cursor = 0;
120 xbt_automaton_propositional_symbol_t ps = NULL;
124 xbt_dynar_foreach(_mc_property_automaton->propositional_symbols, cursor, ps){
125 f = (int_f_void_t)ps->function;
127 xbt_dynar_push_as(pair->prop_ato, int, res);
130 xbt_dynar_push(acceptance_pairs, &pair);
139 static int is_visited_pair(xbt_automaton_state_t st){
141 if(_sg_mc_visited == 0)
144 int raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
148 mc_visited_pair_t new_pair = NULL;
149 new_pair = xbt_new0(s_mc_visited_pair_t, 1);
150 new_pair->automaton_state = st;
151 new_pair->prop_ato = xbt_dynar_new(sizeof(int), NULL);
152 new_pair->system_state = MC_take_snapshot();
154 /* Get values of propositional symbols */
157 unsigned int cursor = 0;
158 xbt_automaton_propositional_symbol_t ps = NULL;
159 xbt_dynar_foreach(_mc_property_automaton->propositional_symbols, cursor, ps){
160 f = (int_f_void_t)ps->function;
162 xbt_dynar_push_as(new_pair->prop_ato, int, res);
167 if(xbt_dynar_is_empty(visited_pairs)){
170 /* New pair visited */
171 xbt_dynar_push(visited_pairs, &new_pair);
184 mc_visited_pair_t pair_test = NULL;
186 xbt_dynar_foreach(visited_pairs, cursor, pair_test){
187 if(XBT_LOG_ISENABLED(mc_liveness, xbt_log_priority_debug))
188 XBT_DEBUG("****** Pair visited #%d ******", cursor + 1);
189 if(xbt_automaton_state_compare(pair_test->automaton_state, st) == 0){
190 if(xbt_automaton_propositional_symbols_compare_value(pair_test->prop_ato, new_pair->prop_ato) == 0){
191 if(snapshot_compare(new_pair->system_state, pair_test->system_state) == 0){
200 XBT_DEBUG("Different values of propositional symbols");
203 XBT_DEBUG("Different automaton state");
207 if(xbt_dynar_length(visited_pairs) == _sg_mc_visited){
208 xbt_dynar_remove_at(visited_pairs, 0, NULL);
211 /* New pair visited */
212 xbt_dynar_push(visited_pairs, &new_pair);
224 static int MC_automaton_evaluate_label(xbt_automaton_exp_label_t l){
228 int left_res = MC_automaton_evaluate_label(l->u.or_and.left_exp);
229 int right_res = MC_automaton_evaluate_label(l->u.or_and.right_exp);
230 return (left_res || right_res);
233 int left_res = MC_automaton_evaluate_label(l->u.or_and.left_exp);
234 int right_res = MC_automaton_evaluate_label(l->u.or_and.right_exp);
235 return (left_res && right_res);
238 int res = MC_automaton_evaluate_label(l->u.exp_not);
242 unsigned int cursor = 0;
243 xbt_automaton_propositional_symbol_t p = NULL;
245 xbt_dynar_foreach(_mc_property_automaton->propositional_symbols, cursor, p){
246 if(strcmp(p->pred, l->u.predicat) == 0){
247 f = (int_f_void_t)p->function;
262 /********* Free functions *********/
264 static void visited_pair_free(mc_visited_pair_t pair){
266 xbt_dynar_free(&(pair->prop_ato));
267 MC_free_snapshot(pair->system_state);
272 static void visited_pair_free_voidp(void *p){
273 visited_pair_free((mc_visited_pair_t) * (void **) p);
276 static void acceptance_pair_free(mc_acceptance_pair_t pair){
278 xbt_dynar_free(&(pair->prop_ato));
279 MC_free_snapshot(pair->system_state);
284 static void acceptance_pair_free_voidp(void *p){
285 acceptance_pair_free((mc_acceptance_pair_t) * (void **) p);
289 /********* DDFS Algorithm *********/
292 void MC_ddfs_init(void){
294 initial_state_liveness->raw_mem_set = (mmalloc_get_current_heap() == raw_heap);
296 XBT_DEBUG("**************************************************");
297 XBT_DEBUG("Double-DFS init");
298 XBT_DEBUG("**************************************************");
300 mc_pair_t mc_initial_pair = NULL;
301 mc_state_t initial_graph_state = NULL;
302 smx_process_t process;
305 MC_wait_for_requests();
309 initial_graph_state = MC_state_new();
310 xbt_swag_foreach(process, simix_global->process_list){
311 if(MC_process_is_enabled(process)){
312 MC_state_interleave_process(initial_graph_state, process);
316 acceptance_pairs = xbt_dynar_new(sizeof(mc_acceptance_pair_t), acceptance_pair_free_voidp);
317 visited_pairs = xbt_dynar_new(sizeof(mc_visited_pair_t), visited_pair_free_voidp);
318 successors = xbt_dynar_new(sizeof(mc_pair_t), NULL);
320 /* Save the initial state */
321 initial_state_liveness->snapshot = MC_take_snapshot();
325 unsigned int cursor = 0;
326 xbt_automaton_state_t automaton_state;
328 xbt_dynar_foreach(_mc_property_automaton->states, cursor, automaton_state){
329 if(automaton_state->type == -1){
332 mc_initial_pair = MC_pair_new(initial_graph_state, automaton_state, MC_state_interleave_size(initial_graph_state));
333 xbt_fifo_unshift(mc_stack_liveness, mc_initial_pair);
337 MC_restore_snapshot(initial_state_liveness->snapshot);
344 if(automaton_state->type == 2){
347 mc_initial_pair = MC_pair_new(initial_graph_state, automaton_state, MC_state_interleave_size(initial_graph_state));
348 xbt_fifo_unshift(mc_stack_liveness, mc_initial_pair);
351 set_acceptance_pair_reached(automaton_state);
354 MC_restore_snapshot(initial_state_liveness->snapshot);
364 if(initial_state_liveness->raw_mem_set)
373 void MC_ddfs(int search_cycle){
375 smx_process_t process;
376 mc_pair_t current_pair = NULL;
378 if(xbt_fifo_size(mc_stack_liveness) == 0)
382 /* Get current pair */
383 current_pair = (mc_pair_t)xbt_fifo_get_item_content(xbt_fifo_get_first_item(mc_stack_liveness));
385 /* Update current state in buchi automaton */
386 _mc_property_automaton->current_state = current_pair->automaton_state;
389 XBT_DEBUG("********************* ( Depth = %d, search_cycle = %d )", xbt_fifo_size(mc_stack_liveness), search_cycle);
391 mc_stats->visited_states++;
394 mc_state_t next_graph_state = NULL;
395 smx_simcall_t req = NULL;
398 xbt_automaton_transition_t transition_succ;
399 unsigned int cursor = 0;
402 mc_pair_t next_pair = NULL;
405 mc_pair_t pair_to_remove;
406 mc_acceptance_pair_t acceptance_pair_to_remove;
408 if(xbt_fifo_size(mc_stack_liveness) < _sg_mc_max_depth){
410 if(current_pair->requests > 0){
412 while((req = MC_state_get_request(current_pair->graph_state, &value)) != NULL){
414 /* Debug information */
416 if(XBT_LOG_ISENABLED(mc_liveness, xbt_log_priority_debug)){
417 req_str = MC_request_to_string(req, value);
418 XBT_DEBUG("Execute: %s", req_str);
422 MC_state_set_executed_request(current_pair->graph_state, req, value);
424 /* Answer the request */
425 SIMIX_simcall_pre(req, value);
427 /* Wait for requests (schedules processes) */
428 MC_wait_for_requests();
432 /* Create the new expanded graph_state */
433 next_graph_state = MC_state_new();
435 /* Get enabled process and insert it in the interleave set of the next graph_state */
436 xbt_swag_foreach(process, simix_global->process_list){
437 if(MC_process_is_enabled(process)){
438 XBT_DEBUG("Process %lu enabled with simcall : %d", process->pid, (&process->simcall)->call);
442 xbt_swag_foreach(process, simix_global->process_list){
443 if(MC_process_is_enabled(process)){
444 MC_state_interleave_process(next_graph_state, process);
448 xbt_dynar_reset(successors);
454 xbt_dynar_foreach(current_pair->automaton_state->out, cursor, transition_succ){
456 res = MC_automaton_evaluate_label(transition_succ->label);
458 if(res == 1){ // enabled transition in automaton
460 next_pair = MC_pair_new(next_graph_state, transition_succ->dst, MC_state_interleave_size(next_graph_state));
461 xbt_dynar_push(successors, &next_pair);
469 xbt_dynar_foreach(current_pair->automaton_state->out, cursor, transition_succ){
471 res = MC_automaton_evaluate_label(transition_succ->label);
473 if(res == 2){ // true transition in automaton
475 next_pair = MC_pair_new(next_graph_state, transition_succ->dst, MC_state_interleave_size(next_graph_state));
476 xbt_dynar_push(successors, &next_pair);
484 xbt_dynar_foreach(successors, cursor, pair_succ){
486 if(search_cycle == 1){
488 if((pair_succ->automaton_state->type == 1) || (pair_succ->automaton_state->type == 2)){
490 if(is_reached_acceptance_pair(pair_succ->automaton_state)){
492 XBT_INFO("Next pair (depth = %d, %u interleave) already reached !", xbt_fifo_size(mc_stack_liveness) + 1, MC_state_interleave_size(pair_succ->graph_state));
494 XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
495 XBT_INFO("| ACCEPTANCE CYCLE |");
496 XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
497 XBT_INFO("Counter-example that violates formula :");
498 MC_show_stack_liveness(mc_stack_liveness);
499 MC_dump_stack_liveness(mc_stack_liveness);
500 MC_print_statistics(mc_stats);
505 if(is_visited_pair(pair_succ->automaton_state)){
507 XBT_DEBUG("Next pair already visited !");
512 XBT_DEBUG("Next pair (depth =%d) -> Acceptance pair (%s)", xbt_fifo_size(mc_stack_liveness) + 1, pair_succ->automaton_state->id);
514 XBT_DEBUG("Acceptance pairs : %lu", xbt_dynar_length(acceptance_pairs));
517 xbt_fifo_unshift(mc_stack_liveness, pair_succ);
520 MC_ddfs(search_cycle);
528 if(is_visited_pair(pair_succ->automaton_state)){
530 XBT_DEBUG("Next pair already visited !");
536 xbt_fifo_unshift(mc_stack_liveness, pair_succ);
539 MC_ddfs(search_cycle);
546 if(is_visited_pair(pair_succ->automaton_state)){
548 XBT_DEBUG("Next pair already visited !");
553 if(((pair_succ->automaton_state->type == 1) || (pair_succ->automaton_state->type == 2))){
555 XBT_DEBUG("Next pair (depth =%d) -> Acceptance pair (%s)", xbt_fifo_size(mc_stack_liveness) + 1, pair_succ->automaton_state->id);
557 set_acceptance_pair_reached(pair_succ->automaton_state);
561 XBT_DEBUG("Acceptance pairs : %lu", xbt_dynar_length(acceptance_pairs));
566 xbt_fifo_unshift(mc_stack_liveness, pair_succ);
569 MC_ddfs(search_cycle);
575 /* Restore system before checking others successors */
576 if(cursor != (xbt_dynar_length(successors) - 1))
577 MC_replay_liveness(mc_stack_liveness, 1);
581 if(MC_state_interleave_size(current_pair->graph_state) > 0){
582 XBT_DEBUG("Backtracking to depth %d", xbt_fifo_size(mc_stack_liveness));
583 MC_replay_liveness(mc_stack_liveness, 0);
590 XBT_DEBUG("No more request to execute in this state, search evolution in Büchi Automaton.");
594 /* Create the new expanded graph_state */
595 next_graph_state = MC_state_new();
597 xbt_dynar_reset(successors);
603 xbt_dynar_foreach(current_pair->automaton_state->out, cursor, transition_succ){
605 res = MC_automaton_evaluate_label(transition_succ->label);
607 if(res == 1){ // enabled transition in automaton
609 next_pair = MC_pair_new(next_graph_state, transition_succ->dst, MC_state_interleave_size(next_graph_state));
610 xbt_dynar_push(successors, &next_pair);
618 xbt_dynar_foreach(current_pair->automaton_state->out, cursor, transition_succ){
620 res = MC_automaton_evaluate_label(transition_succ->label);
622 if(res == 2){ // true transition in automaton
624 next_pair = MC_pair_new(next_graph_state, transition_succ->dst, MC_state_interleave_size(next_graph_state));
625 xbt_dynar_push(successors, &next_pair);
633 xbt_dynar_foreach(successors, cursor, pair_succ){
635 if(search_cycle == 1){
637 if((pair_succ->automaton_state->type == 1) || (pair_succ->automaton_state->type == 2)){
639 if(is_reached_acceptance_pair(pair_succ->automaton_state)){
641 XBT_INFO("Next pair (depth = %d) already reached !", xbt_fifo_size(mc_stack_liveness) + 1);
643 XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
644 XBT_INFO("| ACCEPTANCE CYCLE |");
645 XBT_INFO("*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*");
646 XBT_INFO("Counter-example that violates formula :");
647 MC_show_stack_liveness(mc_stack_liveness);
648 MC_dump_stack_liveness(mc_stack_liveness);
649 MC_print_statistics(mc_stats);
654 if(is_visited_pair(pair_succ->automaton_state)){
656 XBT_DEBUG("Next pair already visited !");
661 XBT_INFO("Next pair (depth = %d) -> Acceptance pair (%s)", xbt_fifo_size(mc_stack_liveness) + 1, pair_succ->automaton_state->id);
663 XBT_INFO("Acceptance pairs : %lu", xbt_dynar_length(acceptance_pairs));
666 xbt_fifo_unshift(mc_stack_liveness, pair_succ);
669 MC_ddfs(search_cycle);
677 if(is_visited_pair(pair_succ->automaton_state)){
679 XBT_DEBUG("Next pair already visited !");
685 xbt_fifo_unshift(mc_stack_liveness, pair_succ);
688 MC_ddfs(search_cycle);
697 if(is_visited_pair(pair_succ->automaton_state)){
699 XBT_DEBUG("Next pair already visited !");
704 if(((pair_succ->automaton_state->type == 1) || (pair_succ->automaton_state->type == 2))){
706 set_acceptance_pair_reached(pair_succ->automaton_state);
710 XBT_INFO("Acceptance pairs : %lu", xbt_dynar_length(acceptance_pairs));
715 xbt_fifo_unshift(mc_stack_liveness, pair_succ);
718 MC_ddfs(search_cycle);
724 /* Restore system before checking others successors */
725 if(cursor != xbt_dynar_length(successors) - 1)
726 MC_replay_liveness(mc_stack_liveness, 1);
734 XBT_WARN("/!\\ Max depth reached ! /!\\ ");
735 if(MC_state_interleave_size(current_pair->graph_state) > 0){
736 XBT_WARN("/!\\ But, there are still processes to interleave. Model-checker will not be able to ensure the soundness of the verification from now. /!\\ ");
737 XBT_WARN("Notice : the default value of max depth is 1000 but you can change it with cfg=model-check/max_depth:value.");
742 if(xbt_fifo_size(mc_stack_liveness) == _sg_mc_max_depth ){
743 XBT_DEBUG("Pair (depth = %d) shifted in stack, maximum depth reached", xbt_fifo_size(mc_stack_liveness) );
745 XBT_DEBUG("Pair (depth = %d) shifted in stack", xbt_fifo_size(mc_stack_liveness) );
750 pair_to_remove = xbt_fifo_shift(mc_stack_liveness);
751 xbt_fifo_remove(mc_stack_liveness, pair_to_remove);
752 pair_to_remove = NULL;
753 if((current_pair->automaton_state->type == 1) || (current_pair->automaton_state->type == 2)){
754 acceptance_pair_to_remove = xbt_dynar_pop_as(acceptance_pairs, mc_acceptance_pair_t);
755 acceptance_pair_free(acceptance_pair_to_remove);
756 acceptance_pair_to_remove = NULL;