Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
726294fcade715d565a5bf499616037d03c4cee6
[simgrid.git] / src / mc / mc_state.cpp
1 /* Copyright (c) 2008-2015. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include <assert.h>
8
9 #include <xbt/log.h>
10 #include <xbt/sysdep.h>
11 #include <xbt/fifo.h>
12
13 #include "src/simix/smx_private.h"
14 #include "src/mc/mc_state.h"
15 #include "src/mc/mc_request.h"
16 #include "src/mc/mc_private.h"
17 #include "src/mc/mc_comm_pattern.h"
18 #include "src/mc/mc_smx.h"
19 #include "src/mc/mc_xbt.hpp"
20
21 using simgrid::mc::remote;
22
23 extern "C" {
24
25 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_state, mc,
26                                 "Logging specific to MC (state)");
27
28 /**
29  * \brief Creates a state data structure used by the exploration algorithm
30  */
31 mc_state_t MC_state_new()
32 {
33   mc_state_t state = xbt_new0(s_mc_state_t, 1);
34
35   state->max_pid = MC_smx_get_maxpid();
36   state->proc_status = xbt_new0(s_mc_procstate_t, state->max_pid);
37   state->system_state = nullptr;
38   state->num = ++mc_stats->expanded_states;
39   state->in_visited_states = 0;
40   state->incomplete_comm_pattern = nullptr;
41   /* Stateful model checking */
42   if((_sg_mc_checkpoint > 0 && (mc_stats->expanded_states % _sg_mc_checkpoint == 0)) ||  _sg_mc_termination){
43     state->system_state = simgrid::mc::take_snapshot(state->num);
44     if(_sg_mc_comms_determinism || _sg_mc_send_determinism){
45       MC_state_copy_incomplete_communications_pattern(state);
46       MC_state_copy_index_communications_pattern(state);
47     }
48   }
49   return state;
50 }
51
52 /**
53  * \brief Deletes a state data structure
54  * \param trans The state to be deleted
55  */
56 void MC_state_delete(mc_state_t state, int free_snapshot){
57   if (state->system_state && free_snapshot){
58     delete state->system_state;
59   }
60   if(_sg_mc_comms_determinism || _sg_mc_send_determinism){
61     xbt_free(state->index_comm);
62     xbt_free(state->incomplete_comm_pattern);
63   }
64   xbt_free(state->proc_status);
65   xbt_free(state);
66 }
67
68 void MC_state_interleave_process(mc_state_t state, smx_process_t process)
69 {
70   assert(state);
71   state->proc_status[process->pid].state = MC_INTERLEAVE;
72   state->proc_status[process->pid].interleave_count = 0;
73 }
74
75 void MC_state_remove_interleave_process(mc_state_t state, smx_process_t process)
76 {
77   if (state->proc_status[process->pid].state == MC_INTERLEAVE)
78     state->proc_status[process->pid].state = MC_DONE;
79 }
80
81 unsigned int MC_state_interleave_size(mc_state_t state)
82 {
83   unsigned int i, size = 0;
84
85   for (i = 0; i < state->max_pid; i++) {
86     if ((state->proc_status[i].state == MC_INTERLEAVE)
87         || (state->proc_status[i].state == MC_MORE_INTERLEAVE))
88       size++;
89   }
90
91   return size;
92 }
93
94 int MC_state_process_is_done(mc_state_t state, smx_process_t process)
95 {
96   return state->proc_status[process->pid].state == MC_DONE ? TRUE : FALSE;
97 }
98
99 void MC_state_set_executed_request(mc_state_t state, smx_simcall_t req,
100                                    int value)
101 {
102   state->executed_req = *req;
103   state->req_num = value;
104
105   /* The waitany and testany request are transformed into a wait or test request over the
106    * corresponding communication action so it can be treated later by the dependence
107    * function. */
108   switch (req->call) {
109   case SIMCALL_COMM_WAITANY: {
110     state->internal_req.call = SIMCALL_COMM_WAIT;
111     state->internal_req.issuer = req->issuer;
112     smx_synchro_t remote_comm;
113     read_element(mc_model_checker->process(),
114       &remote_comm, remote(simcall_comm_waitany__get__comms(req)),
115       value, sizeof(remote_comm));
116     mc_model_checker->process().read(&state->internal_comm, remote(remote_comm));
117     simcall_comm_wait__set__comm(&state->internal_req, &state->internal_comm);
118     simcall_comm_wait__set__timeout(&state->internal_req, 0);
119     break;
120   }
121
122   case SIMCALL_COMM_TESTANY:
123     state->internal_req.call = SIMCALL_COMM_TEST;
124     state->internal_req.issuer = req->issuer;
125
126     if (value > 0) {
127       smx_synchro_t remote_comm;
128       read_element(mc_model_checker->process(),
129         &remote_comm, remote(simcall_comm_testany__get__comms(req)),
130         value, sizeof(remote_comm));
131       mc_model_checker->process().read(&state->internal_comm, remote(remote_comm));
132     }
133
134     simcall_comm_test__set__comm(&state->internal_req, &state->internal_comm);
135     simcall_comm_test__set__result(&state->internal_req, value);
136     break;
137
138   case SIMCALL_COMM_WAIT:
139     state->internal_req = *req;
140     mc_model_checker->process().read_bytes(&state->internal_comm ,
141       sizeof(state->internal_comm), remote(simcall_comm_wait__get__comm(req)));
142     simcall_comm_wait__set__comm(&state->executed_req, &state->internal_comm);
143     simcall_comm_wait__set__comm(&state->internal_req, &state->internal_comm);
144     break;
145
146   case SIMCALL_COMM_TEST:
147     state->internal_req = *req;
148     mc_model_checker->process().read_bytes(&state->internal_comm,
149       sizeof(state->internal_comm), remote(simcall_comm_test__get__comm(req)));
150     simcall_comm_test__set__comm(&state->executed_req, &state->internal_comm);
151     simcall_comm_test__set__comm(&state->internal_req, &state->internal_comm);
152     break;
153
154   case SIMCALL_MC_RANDOM: {
155     state->internal_req = *req;
156     int random_max = simcall_mc_random__get__max(req);
157     if (value != random_max) {
158       for (auto& p : mc_model_checker->process().simix_processes()) {
159         mc_procstate_t procstate = &state->proc_status[p.copy.pid];
160         const smx_process_t issuer = MC_smx_simcall_get_issuer(req);
161         if (p.copy.pid == issuer->pid) {
162           procstate->state = MC_MORE_INTERLEAVE;
163           break;
164         }
165       }
166     }
167     break;
168   }
169
170   default:
171     state->internal_req = *req;
172     break;
173   }
174 }
175
176 smx_simcall_t MC_state_get_executed_request(mc_state_t state, int *value)
177 {
178   *value = state->req_num;
179   return &state->executed_req;
180 }
181
182 smx_simcall_t MC_state_get_internal_request(mc_state_t state)
183 {
184   return &state->internal_req;
185 }
186
187 static inline smx_simcall_t MC_state_get_request_for_process(
188   mc_state_t state, int*value, smx_process_t process)
189 {
190   mc_procstate_t procstate = &state->proc_status[process->pid];
191
192   if (procstate->state != MC_INTERLEAVE
193       && procstate->state != MC_MORE_INTERLEAVE)
194       return nullptr;
195   if (!MC_process_is_enabled(process))
196     return nullptr;
197
198   switch (process->simcall.call) {
199
200       case SIMCALL_COMM_WAITANY:
201         *value = -1;
202         while (procstate->interleave_count <
203               read_length(mc_model_checker->process(),
204                 remote(simcall_comm_waitany__get__comms(&process->simcall)))) {
205           if (MC_request_is_enabled_by_idx
206               (&process->simcall, procstate->interleave_count++)) {
207             *value = procstate->interleave_count - 1;
208             break;
209           }
210         }
211
212         if (procstate->interleave_count >=
213             simgrid::mc::read_length(mc_model_checker->process(),
214               simgrid::mc::remote(simcall_comm_waitany__get__comms(&process->simcall))))
215           procstate->state = MC_DONE;
216
217         if (*value != -1)
218           return &process->simcall;
219
220         break;
221
222       case SIMCALL_COMM_TESTANY: {
223         unsigned start_count = procstate->interleave_count;
224         *value = -1;
225         while (procstate->interleave_count <
226                 read_length(mc_model_checker->process(),
227                   remote(simcall_comm_testany__get__comms(&process->simcall)))) {
228           if (MC_request_is_enabled_by_idx
229               (&process->simcall, procstate->interleave_count++)) {
230             *value = procstate->interleave_count - 1;
231             break;
232           }
233         }
234
235         if (procstate->interleave_count >=
236             read_length(mc_model_checker->process(),
237               remote(simcall_comm_testany__get__comms(&process->simcall))))
238           procstate->state = MC_DONE;
239
240         if (*value != -1 || start_count == 0)
241           return &process->simcall;
242
243         break;
244       }
245
246       case SIMCALL_COMM_WAIT: {
247         smx_synchro_t remote_act = simcall_comm_wait__get__comm(&process->simcall);
248         s_smx_synchro_t act;
249         mc_model_checker->process().read_bytes(
250           &act, sizeof(act), remote(remote_act));
251         if (act.comm.src_proc && act.comm.dst_proc) {
252           *value = 0;
253         } else {
254           if (act.comm.src_proc == nullptr && act.comm.type == SIMIX_COMM_READY
255               && act.comm.detached == 1)
256             *value = 0;
257           else
258             *value = -1;
259         }
260         procstate->state = MC_DONE;
261         return &process->simcall;
262       }
263
264       case SIMCALL_MC_RANDOM:
265         if (procstate->state == MC_INTERLEAVE)
266           *value = simcall_mc_random__get__min(&process->simcall);
267         else {
268           if (state->req_num < simcall_mc_random__get__max(&process->simcall))
269             *value = state->req_num + 1;
270         }
271         procstate->state = MC_DONE;
272         return &process->simcall;
273
274       default:
275         procstate->state = MC_DONE;
276         *value = 0;
277         return &process->simcall;
278   }
279   return nullptr;
280 }
281
282 smx_simcall_t MC_state_get_request(mc_state_t state, int *value)
283 {
284   for (auto& p : mc_model_checker->process().simix_processes()) {
285     smx_simcall_t res = MC_state_get_request_for_process(state, value, &p.copy);
286     if (res)
287       return res;
288   }
289   return nullptr;
290 }
291
292 }