Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] Remove __STDC_FORMAT_MACROS
[simgrid.git] / src / mc / mc_base.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 <cassert>
8
9 #include <simgrid_config.h>
10
11 #include <xbt/log.h>
12 #include <xbt/asserts.h>
13 #include <xbt/dynar.h>
14
15 #include <simgrid/simix.h>
16
17 #include "src/mc/mc_base.h"
18 #include "src/simix/smx_private.h"
19 #include "src/mc/mc_replay.h"
20 #include "mc/mc.h"
21 #include "src/mc/mc_protocol.h"
22
23 #if HAVE_MC
24 #include "src/mc/mc_request.h"
25 #include "src/mc/Process.hpp"
26 #include "src/mc/ModelChecker.hpp"
27 #include "src/mc/mc_smx.h"
28 #endif
29
30 #if HAVE_MC
31 using simgrid::mc::remote;
32 #endif
33
34 XBT_LOG_NEW_CATEGORY(mc, "All MC categories");
35
36 int MC_random(int min, int max)
37 {
38 #if HAVE_MC
39   xbt_assert(mc_model_checker == nullptr);
40   /* TODO, if the MC is disabled we do not really need to make a simcall for
41    * this :) */
42 #endif
43   return simcall_mc_random(min, max);
44 }
45
46 namespace simgrid {
47 namespace mc {
48
49 void wait_for_requests(void)
50 {
51 #if HAVE_MC
52   xbt_assert(mc_model_checker == nullptr);
53 #endif
54
55   smx_process_t process;
56   smx_simcall_t req;
57   unsigned int iter;
58
59   while (!xbt_dynar_is_empty(simix_global->process_to_run)) {
60     SIMIX_process_runall();
61     xbt_dynar_foreach(simix_global->process_that_ran, iter, process) {
62       req = &process->simcall;
63       if (req->call != SIMCALL_NONE && !simgrid::mc::request_is_visible(req))
64         SIMIX_simcall_handle(req, 0);
65     }
66   }
67 }
68
69 // Called from both MCer and MCed:
70 bool request_is_enabled(smx_simcall_t req)
71 {
72   unsigned int index = 0;
73   smx_synchro_t act = 0;
74 #if HAVE_MC
75   s_smx_synchro_t temp_synchro;
76 #endif
77
78   switch (req->call) {
79   case SIMCALL_NONE:
80     return false;
81
82   case SIMCALL_COMM_WAIT:
83     /* FIXME: check also that src and dst processes are not suspended */
84     act = simcall_comm_wait__get__comm(req);
85
86 #if HAVE_MC
87     // Fetch from MCed memory:
88     if (mc_model_checker != nullptr) {
89       mc_model_checker->process().read(&temp_synchro, remote(act));
90       act = &temp_synchro;
91     }
92 #endif
93
94     if (simcall_comm_wait__get__timeout(req) >= 0) {
95       /* If it has a timeout it will be always be enabled, because even if the
96        * communication is not ready, it can timeout and won't block. */
97       if (_sg_mc_timeout == 1)
98         return true;
99     }
100     /* On the other hand if it hasn't a timeout, check if the comm is ready.*/
101     else if (act->comm.detached && act->comm.src_proc == nullptr
102           && act->comm.type == SIMIX_COMM_READY)
103         return (act->comm.dst_proc != nullptr);
104     return (act->comm.src_proc && act->comm.dst_proc);
105
106   case SIMCALL_COMM_WAITANY: {
107     xbt_dynar_t comms;
108 #if HAVE_MC
109
110     s_xbt_dynar_t comms_buffer;
111     size_t buffer_size = 0;
112     if (mc_model_checker != nullptr) {
113       // Read dynar:
114       mc_model_checker->process().read(
115         &comms_buffer, remote(simcall_comm_waitany__get__comms(req)));
116       assert(comms_buffer.elmsize == sizeof(act));
117       buffer_size = comms_buffer.elmsize * comms_buffer.used;
118       comms = &comms_buffer;
119     } else
120       comms = simcall_comm_waitany__get__comms(req);
121
122     // Read all the dynar buffer:
123     char buffer[buffer_size];
124     if (mc_model_checker != nullptr)
125       mc_model_checker->process().read_bytes(buffer, sizeof(buffer),
126         remote(comms->data));
127 #else
128     comms = simcall_comm_waitany__get__comms(req);
129 #endif
130
131     for (index = 0; index < comms->used; ++index) {
132 #if HAVE_MC
133       // Fetch act from MCed memory:
134       if (mc_model_checker != nullptr) {
135         memcpy(&act, buffer + comms->elmsize * index, sizeof(act));
136         mc_model_checker->process().read(&temp_synchro, remote(act));
137         act = &temp_synchro;
138       }
139       else
140 #endif
141         act = xbt_dynar_get_as(comms, index, smx_synchro_t);
142       if (act->comm.src_proc && act->comm.dst_proc)
143         return true;
144     }
145     return false;
146   }
147
148   case SIMCALL_MUTEX_TRYLOCK:
149     return true;
150
151   case SIMCALL_MUTEX_LOCK: {
152     smx_mutex_t mutex = simcall_mutex_lock__get__mutex(req);
153 #if HAVE_MC
154     s_smx_mutex_t temp_mutex;
155     if (mc_model_checker != nullptr) {
156       mc_model_checker->process().read(&temp_mutex, remote(mutex));
157       mutex = &temp_mutex;
158     }
159 #endif
160
161     if(mutex->owner == nullptr)
162       return true;
163 #if HAVE_MC
164     else if (mc_model_checker != nullptr) {
165       simgrid::mc::Process& modelchecked = mc_model_checker->process();
166       // TODO, *(mutex->owner) :/
167       return modelchecked.resolveProcess(simgrid::mc::remote(mutex->owner))->pid
168         == modelchecked.resolveProcess(simgrid::mc::remote(req->issuer))->pid;
169     }
170 #endif
171     else
172       return mutex->owner->pid == req->issuer->pid;
173     }
174
175   default:
176     /* The rest of the requests are always enabled */
177     return true;
178   }
179 }
180
181 bool request_is_visible(smx_simcall_t req)
182 {
183   return req->call == SIMCALL_COMM_ISEND
184       || req->call == SIMCALL_COMM_IRECV
185       || req->call == SIMCALL_COMM_WAIT
186       || req->call == SIMCALL_COMM_WAITANY
187       || req->call == SIMCALL_COMM_TEST
188       || req->call == SIMCALL_COMM_TESTANY
189       || req->call == SIMCALL_MC_RANDOM
190       || req->call == SIMCALL_MUTEX_LOCK
191       || req->call == SIMCALL_MUTEX_TRYLOCK
192       ;
193 }
194
195 }
196 }
197
198 static int prng_random(int min, int max)
199 {
200   unsigned long output_size = ((unsigned long) max - (unsigned long) min) + 1;
201   unsigned long input_size = (unsigned long) RAND_MAX + 1;
202   unsigned long reject_size = input_size % output_size;
203   unsigned long accept_size = input_size - reject_size; // module*accept_size
204
205   // Use rejection in order to avoid skew
206   unsigned long x;
207   do {
208 #ifndef _WIN32
209     x = (unsigned long) random();
210 #else
211     x = (unsigned long) rand();
212 #endif
213   } while( x >= accept_size );
214   return min + (x % output_size);
215 }
216
217 int simcall_HANDLER_mc_random(smx_simcall_t simcall, int min, int max)
218 {
219   if (!MC_is_active() && !MC_record_path)
220     return prng_random(min, max);
221   return simcall->mc_value;
222 }