Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Split inspector::is_pending() in two logical parts
[simgrid.git] / src / mc / mc_base.cpp
1 /* Copyright (c) 2008-2021. The SimGrid Team. All rights reserved.          */
2
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. */
5
6 #include "src/mc/mc_base.h"
7 #include "mc/mc.h"
8 #include "src/kernel/activity/CommImpl.hpp"
9 #include "src/kernel/activity/MutexImpl.hpp"
10 #include "src/mc/checker/SimcallInspector.hpp"
11 #include "src/mc/mc_config.hpp"
12 #include "src/mc/mc_replay.hpp"
13 #include "src/simix/smx_private.hpp"
14
15 #include "xbt/random.hpp"
16
17 #if SIMGRID_HAVE_MC
18 #include "src/mc/ModelChecker.hpp"
19 #include "src/mc/Session.hpp"
20 #include "src/mc/remote/RemoteSimulation.hpp"
21
22 using simgrid::mc::remote;
23 #endif
24
25 XBT_LOG_NEW_DEFAULT_CATEGORY(mc, "All MC categories");
26
27 int MC_random(int min, int max)
28 {
29 #if SIMGRID_HAVE_MC
30   xbt_assert(mc_model_checker == nullptr);
31 #endif
32   /* TODO, if the MC is disabled we do not really need to make a simcall for this :) */
33   return simcall_mc_random(min, max);
34 }
35
36 namespace simgrid {
37 namespace mc {
38
39 void wait_for_requests()
40 {
41 #if SIMGRID_HAVE_MC
42   xbt_assert(mc_model_checker == nullptr, "This must be called from the client");
43 #endif
44   while (not simix_global->actors_to_run.empty()) {
45     simix_global->run_all_actors();
46     for (smx_actor_t const& process : simix_global->actors_that_ran) {
47       const s_smx_simcall* req = &process->simcall_;
48       if (req->call_ != simix::Simcall::NONE && not simgrid::mc::request_is_visible(req))
49         process->simcall_handle(0);
50     }
51   }
52 #if SIMGRID_HAVE_MC
53   xbt_dynar_reset(simix_global->actors_vector);
54   for (std::pair<const aid_t, smx_actor_t> const& kv : simix_global->process_list) {
55     auto actor = kv.second;
56     if (actor->simcall_.inspector_ != nullptr)
57       actor->simcall_.mc_max_consider_ = actor->simcall_.inspector_->get_max_consider();
58     xbt_dynar_push_as(simix_global->actors_vector, smx_actor_t, actor);
59   }
60 #endif
61 }
62
63 /** @brief returns if there this transition can proceed in a finite amount of time
64  *
65  * It is used in the model-checker to not get into self-deadlock where it would execute a never ending transition.
66  *
67  * Only WAIT operations (on comm, on mutex, etc) can ever return false because they could lock the MC exploration.
68  * Wait operations are OK and return true in only two situations:
69  *  - if the wait will succeed immediately (if both peer of the comm are there already or if the mutex is available)
70  *  - if a timeout is provided, because we can fire the timeout if the transition is not ready without blocking in this
71  * transition for ever.
72  *
73  */
74 // Called from both MCer and MCed:
75 bool actor_is_enabled(smx_actor_t actor)
76 {
77 // #del
78 #if SIMGRID_HAVE_MC
79   // If in the MCer, ask the client app since it has all the data
80   if (mc_model_checker != nullptr) {
81     return simgrid::mc::session->actor_is_enabled(actor->get_pid());
82   }
83 #endif
84 // #
85
86   // Now, we are in the client app, no need for remote memory reading.
87   smx_simcall_t req = &actor->simcall_;
88
89   if (req->inspector_ != nullptr)
90     return req->inspector_->is_enabled();
91
92   using simix::Simcall;
93   switch (req->call_) {
94     case Simcall::NONE:
95       return false;
96
97     case Simcall::COMM_WAIT: {
98       /* FIXME: check also that src and dst processes are not suspended */
99       const kernel::activity::CommImpl* act = simcall_comm_wait__getraw__comm(req);
100
101       if (act->src_timeout_ || act->dst_timeout_) {
102         /* If it has a timeout it will be always be enabled (regardless of who declared the timeout),
103          * because even if the communication is not ready, it can timeout and won't block. */
104         if (_sg_mc_timeout == 1)
105           return true;
106       }
107       /* On the other hand if it hasn't a timeout, check if the comm is ready.*/
108       else if (act->detached() && act->src_actor_ == nullptr && act->state_ == simgrid::kernel::activity::State::READY)
109         return (act->dst_actor_ != nullptr);
110       return (act->src_actor_ && act->dst_actor_);
111     }
112
113     case Simcall::COMM_WAITANY: {
114       simgrid::kernel::activity::CommImpl** comms = simcall_comm_waitany__get__comms(req);
115       size_t count                                = simcall_comm_waitany__get__count(req);
116       for (unsigned int index = 0; index < count; ++index) {
117         auto const* comm = comms[index];
118         if (comm->src_actor_ && comm->dst_actor_)
119           return true;
120       }
121       return false;
122     }
123
124     case Simcall::MUTEX_LOCK: {
125       const kernel::activity::MutexImpl* mutex = simcall_mutex_lock__get__mutex(req);
126
127       if (mutex->get_owner() == nullptr)
128         return true;
129       return mutex->get_owner()->get_pid() == req->issuer_->get_pid();
130     }
131
132     case Simcall::SEM_ACQUIRE: {
133       static int warned = 0;
134       if (not warned)
135         XBT_INFO("Using semaphore in model-checked code is still experimental. Use at your own risk");
136       warned = 1;
137       return true;
138     }
139
140     case Simcall::COND_WAIT: {
141       static int warned = 0;
142       if (not warned)
143         XBT_INFO("Using condition variables in model-checked code is still experimental. Use at your own risk");
144       warned = 1;
145       return true;
146     }
147
148     default:
149       /* The rest of the requests are always enabled */
150       return true;
151   }
152 }
153
154 /* This is the list of requests that are visible from the checker algorithm.
155  * Any other requests are handled right away on the application side.
156  */
157 bool request_is_visible(const s_smx_simcall* req)
158 {
159 #if SIMGRID_HAVE_MC
160   xbt_assert(mc_model_checker == nullptr, "This should be called from the client side");
161 #endif
162   if (req->inspector_ != nullptr)
163     return req->inspector_->is_visible();
164
165   using simix::Simcall;
166   return req->call_ == Simcall::COMM_ISEND || req->call_ == Simcall::COMM_IRECV || req->call_ == Simcall::COMM_WAIT ||
167          req->call_ == Simcall::COMM_WAITANY || req->call_ == Simcall::COMM_TEST ||
168          req->call_ == Simcall::COMM_TESTANY || req->call_ == Simcall::MUTEX_LOCK ||
169          req->call_ == Simcall::MUTEX_TRYLOCK || req->call_ == Simcall::MUTEX_UNLOCK;
170 }
171
172 }
173 }