Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Implement pthread_join in MC mode for sthread
authorMartin Quinson <martin.quinson@ens-rennes.fr>
Sun, 16 Oct 2022 09:54:03 +0000 (11:54 +0200)
committerMartin Quinson <martin.quinson@ens-rennes.fr>
Sun, 16 Oct 2022 10:58:21 +0000 (12:58 +0200)
12 files changed:
ChangeLog
src/kernel/actor/SimcallObserver.cpp
src/kernel/actor/SimcallObserver.hpp
src/mc/remote/AppSide.cpp
src/mc/transition/Transition.cpp
src/mc/transition/Transition.hpp
src/mc/transition/TransitionActorJoin.cpp [new file with mode: 0644]
src/mc/transition/TransitionActorJoin.hpp [new file with mode: 0644]
src/s4u/s4u_Actor.cpp
src/sthread/sthread.c
src/sthread/sthread_impl.cpp
tools/cmake/DefinePackages.cmake

index e782fb0..e3294b2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -16,6 +16,9 @@ Models:
    - See also "A Flow-Level Wi-Fi Model for Large Scale Network Simulation"
      https://hal.archives-ouvertes.fr/hal-03777726
 
+sthread:
+ - Implement pthread_join in MC mode.
+
 Fixed bugs (FG#.. -> FramaGit bugs; FG!.. -> FG merge requests)
  (FG: issues on Framagit; GH: issues on GitHub)
  - FG!118: Wi-Fi callback mechanism
index 87991cc..294fc3a 100644 (file)
@@ -16,10 +16,6 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_observer, mc, "Logging specific to MC simcall
 
 namespace simgrid::kernel::actor {
 
-void SimcallObserver::serialize(std::stringstream& stream) const
-{
-  stream << (short)mc::Transition::Type::UNKNOWN;
-}
 void RandomSimcall::serialize(std::stringstream& stream) const
 {
   stream << (short)mc::Transition::Type::RANDOM << ' ';
@@ -45,4 +41,22 @@ bool ConditionWaitSimcall::is_enabled()
   }
   return true;
 }
+void ConditionWaitSimcall::serialize(std::stringstream& stream) const
+{
+  THROW_UNIMPLEMENTED;
+}
+
+ActorJoinSimcall::ActorJoinSimcall(ActorImpl* actor, ActorImpl* other, double timeout)
+    : SimcallObserver(actor), other_(s4u::ActorPtr(other->get_iface())), timeout_(timeout)
+{
+}
+bool ActorJoinSimcall::is_enabled()
+{
+  return other_->get_impl()->wannadie();
+}
+void ActorJoinSimcall::serialize(std::stringstream& stream) const
+{
+  stream << (short)mc::Transition::Type::ACTOR_JOIN << ' ';
+  stream << other_->get_pid() << ' ' << static_cast<bool>(timeout_ > 0);
+}
 } // namespace simgrid::kernel::actor
index a4095e4..909ebd1 100644 (file)
@@ -53,10 +53,11 @@ public:
   }
 
   /** Serialize to the given string buffer */
-  virtual void serialize(std::stringstream& stream) const;
+  virtual void serialize(std::stringstream& stream) const = 0;
 
-  /** Some simcalls may only be observable under some conditions.
-   * Most simcalls are not visible from the MC because they don't have an observer at all. */
+  /** Whether the MC should see this simcall.
+   * Simcall that don't have an observer (ie, most of them) are not visible from the MC, but if there is an observer,
+   * they are observable by default. */
   virtual bool is_visible() const { return true; }
 };
 
@@ -99,13 +100,25 @@ public:
       : ResultingSimcall(actor, false), cond_(cond), mutex_(mutex), timeout_(timeout)
   {
   }
+  void serialize(std::stringstream& stream) const override;
   bool is_enabled() override;
-  bool is_visible() const override { return false; }
   activity::ConditionVariableImpl* get_cond() const { return cond_; }
   activity::MutexImpl* get_mutex() const { return mutex_; }
   double get_timeout() const { return timeout_; }
 };
 
+class ActorJoinSimcall final : public SimcallObserver {
+  s4u::ActorPtr const other_; // We need a Ptr to ensure access to the actor after its end, but Ptr requires s4u
+  const double timeout_;
+
+public:
+  ActorJoinSimcall(ActorImpl* actor, ActorImpl* other, double timeout = -1.0);
+  void serialize(std::stringstream& stream) const override;
+  bool is_enabled() override;
+
+  s4u::ActorPtr get_other_actor() const { return other_; }
+  double get_timeout() const { return timeout_; }
+};
 } // namespace simgrid::kernel::actor
 
 #endif
index e74e4d4..5410898 100644 (file)
@@ -145,6 +145,7 @@ void AppSide::handle_actors_status() const
 {
   auto const& actor_list = kernel::EngineImpl::get_instance()->get_actor_list();
   int count              = actor_list.size();
+  XBT_DEBUG("Serialize the actors to answer ACTORS_STATUS from the checker. %d actors to go.", count);
 
   struct s_mc_message_actors_status_answer_t answer {
     MessageType::ACTORS_STATUS_REPLY, count
index 3fb8ced..5209927 100644 (file)
@@ -10,6 +10,7 @@
 
 #if SIMGRID_HAVE_MC
 #include "src/mc/ModelChecker.hpp"
+#include "src/mc/transition/TransitionActorJoin.hpp"
 #include "src/mc/transition/TransitionAny.hpp"
 #include "src/mc/transition/TransitionComm.hpp"
 #include "src/mc/transition/TransitionRandom.hpp"
@@ -91,13 +92,18 @@ Transition* deserialize_transition(aid_t issuer, int times_considered, std::stri
     case Transition::Type::SEM_WAIT:
       return new SemaphoreTransition(issuer, times_considered, simcall, stream);
 
+    case Transition::Type::ACTOR_JOIN:
+      return new ActorJoinTransition(issuer, times_considered, stream);
+
     case Transition::Type::UNKNOWN:
       return new Transition(Transition::Type::UNKNOWN, issuer, times_considered);
 
     default:
       break;
   }
-  xbt_die("Invalid transition type %d received", type);
+  xbt_die("Invalid transition type %d received. Did you implement a new observer in the app without implementing the "
+          "corresponding transition in the checker?",
+          type);
 #else
   xbt_die("Deserializing transitions is only interesting in MC mode.");
 #endif
index 19e30b9..91f02b9 100644 (file)
@@ -37,6 +37,7 @@ public:
                          COMM_RECV, COMM_SEND, COMM_TEST, COMM_WAIT, /* Alphabetical ordering of COMM_* */
                          MUTEX_LOCK, MUTEX_TEST, MUTEX_TRYLOCK, MUTEX_UNLOCK, MUTEX_WAIT, /* alphabetical */
                          SEM_LOCK, SEM_UNLOCK, SEM_WAIT, /* alphabetical ordering of SEM transitions */
+                         ACTOR_JOIN,
                          /* UNKNOWN must be last */ UNKNOWN);
   Type type_ = Type::UNKNOWN;
 
diff --git a/src/mc/transition/TransitionActorJoin.cpp b/src/mc/transition/TransitionActorJoin.cpp
new file mode 100644 (file)
index 0000000..2f4b017
--- /dev/null
@@ -0,0 +1,40 @@
+/* Copyright (c) 2015-2022. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "src/mc/transition/TransitionActorJoin.hpp"
+#include "xbt/asserts.h"
+#include <simgrid/config.h>
+#if SIMGRID_HAVE_MC
+#include "src/mc/ModelChecker.hpp"
+#include "src/mc/api/RemoteApp.hpp"
+#include "src/mc/api/State.hpp"
+#endif
+
+#include <sstream>
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_trans_actorlifecycle, mc_transition,
+                                "Logging specific to MC transitions about actors' lifecycle: joining, ending");
+
+namespace simgrid::mc {
+
+ActorJoinTransition::ActorJoinTransition(aid_t issuer, int times_considered, std::stringstream& stream)
+    : Transition(Type::ACTOR_JOIN, issuer, times_considered)
+{
+  xbt_assert(stream >> target_ >> timeout_);
+  XBT_DEBUG("ActorJoinTransition target:%ld, %s ", target_, (timeout_ ? "timeout" : "no-timeout"));
+}
+std::string ActorJoinTransition::to_string(bool verbose) const
+{
+  return xbt::string_printf("ActorJoin(target %ld, %s)", target_, (timeout_ ? "timeout" : "no timeout"));
+}
+bool ActorJoinTransition::depends(const Transition* other) const
+{
+  // Joining is indep with any other transitions:
+  // - It is only enabled once the target ends, and after this point it's enabled no matter what
+  // - Other joins don't affect it, and it does not impact on the enabledness of any other transition
+  return false;
+}
+
+} // namespace simgrid::mc
diff --git a/src/mc/transition/TransitionActorJoin.hpp b/src/mc/transition/TransitionActorJoin.hpp
new file mode 100644 (file)
index 0000000..da06a33
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (c) 2015-2022. The SimGrid Team. All rights reserved.          */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_MC_TRANSITION_ACTOR_JOIN_HPP
+#define SIMGRID_MC_TRANSITION_ACTOR_JOIN_HPP
+
+#include "src/kernel/actor/SimcallObserver.hpp"
+#include "src/mc/transition/Transition.hpp"
+
+#include <cstdint>
+#include <sstream>
+#include <string>
+
+namespace simgrid::mc {
+
+class ActorJoinTransition : public Transition {
+  bool timeout_;
+  aid_t target_;
+
+public:
+  ActorJoinTransition(aid_t issuer, int times_considered, std::stringstream& stream);
+  std::string to_string(bool verbose) const override;
+  bool depends(const Transition* other) const override;
+
+  bool get_timeout() const { return timeout_; }
+  /** Target ID */
+  aid_t get_target() const { return target_; }
+};
+
+} // namespace simgrid::mc
+
+#endif
index 8c0fc2e..e4ec4be 100644 (file)
@@ -108,20 +108,21 @@ void Actor::join() const
 
 void Actor::join(double timeout) const
 {
-  xbt_assert(not(MC_is_active() || MC_record_replay_is_active()),
-             "Actor::join() is not usable in MC yet. Please report this bug.");
-
   kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
   const kernel::actor::ActorImpl* target = pimpl_;
-  kernel::actor::simcall_blocking([issuer, target, timeout] {
-    if (target->wannadie()) {
-      // The joined actor is already finished, just wake up the issuer right away
-      issuer->simcall_answer();
-    } else {
-      kernel::activity::ActivityImplPtr sync = issuer->join(target, timeout);
-      sync->register_simcall(&issuer->simcall_);
-    }
-  });
+  kernel::actor::ActorJoinSimcall observer{issuer, get_impl(), timeout};
+
+  kernel::actor::simcall_blocking(
+      [issuer, target, timeout] {
+        if (target->wannadie()) {
+          // The joined actor is already finished, just wake up the issuer right away
+          issuer->simcall_answer();
+        } else {
+          kernel::activity::ActivityImplPtr sync = issuer->join(target, timeout);
+          sync->register_simcall(&issuer->simcall_);
+        }
+      },
+      &observer);
 }
 
 Actor* Actor::set_auto_restart(bool autorestart)
index a52fec8..117156f 100644 (file)
@@ -78,7 +78,6 @@ int pthread_join(pthread_t thread, void** retval)
 {
   if (raw_pthread_join == NULL)
     intercepter_init();
-
   if (sthread_inside_simgrid)
     return raw_pthread_join(thread, retval);
 
index 9eb1a91..4ef0265 100644 (file)
@@ -46,7 +46,7 @@ int sthread_main(int argc, char** argv, char** envp, int (*raw_main)(int, char**
 
   /* Launch the user's main() on an actor */
   sthread_enable();
-  sg4::ActorPtr main_actor = sg4::Actor::create("tid 0", lilibeth, raw_main, argc, argv, envp);
+  sg4::ActorPtr main_actor = sg4::Actor::create("main thread", lilibeth, raw_main, argc, argv, envp);
 
   XBT_INFO("Starting the simulation.");
   sg4::Engine::get_instance()->run();
index 2ade517..e9b7060 100644 (file)
@@ -622,6 +622,8 @@ set(MC_SRC
   src/mc/sosp/Snapshot.hpp
 
   src/mc/transition/Transition.hpp
+  src/mc/transition/TransitionActorJoin.cpp
+  src/mc/transition/TransitionActorJoin.hpp
   src/mc/transition/TransitionAny.cpp
   src/mc/transition/TransitionAny.hpp
   src/mc/transition/TransitionComm.cpp