Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Implement MutexImpl::lock_async
authorMartin Quinson <martin.quinson@ens-rennes.fr>
Tue, 22 Feb 2022 23:26:17 +0000 (00:26 +0100)
committerMartin Quinson <martin.quinson@ens-rennes.fr>
Wed, 23 Feb 2022 00:20:01 +0000 (01:20 +0100)
15 files changed:
MANIFEST.in
include/simgrid/forward.h
src/kernel/activity/ActivityImpl.cpp
src/kernel/activity/ActivityImpl.hpp
src/kernel/activity/ConditionVariableImpl.cpp
src/kernel/activity/MutexImpl.cpp
src/kernel/activity/MutexImpl.hpp
src/kernel/activity/SemaphoreImpl.cpp
src/kernel/actor/CommObserver.cpp
src/kernel/actor/MutexObserver.cpp [new file with mode: 0644]
src/kernel/actor/MutexObserver.hpp [new file with mode: 0644]
src/kernel/actor/SimcallObserver.cpp
src/kernel/actor/SimcallObserver.hpp
src/s4u/s4u_Mutex.cpp
tools/cmake/DefinePackages.cmake

index ea185af..ee5ec51 100644 (file)
@@ -2260,6 +2260,8 @@ include src/kernel/actor/ActorImpl.cpp
 include src/kernel/actor/ActorImpl.hpp
 include src/kernel/actor/CommObserver.cpp
 include src/kernel/actor/CommObserver.hpp
+include src/kernel/actor/MutexObserver.cpp
+include src/kernel/actor/MutexObserver.hpp
 include src/kernel/actor/SimcallObserver.cpp
 include src/kernel/actor/SimcallObserver.hpp
 include src/kernel/context/Context.cpp
index 84daec4..f723289 100644 (file)
@@ -138,10 +138,12 @@ namespace activity {
   using IoImplPtr = boost::intrusive_ptr<IoImpl>;
   class MutexImpl;
   using MutexImplPtr = boost::intrusive_ptr<MutexImpl>;
+  class MutexAcquisitionImpl;
+  using MutexAcquisitionImplPtr = boost::intrusive_ptr<MutexAcquisitionImpl>;
   XBT_PUBLIC void intrusive_ptr_add_ref(MutexImpl* mutex);
   XBT_PUBLIC void intrusive_ptr_release(MutexImpl* mutex);
   class SynchroImpl;
-  using RawImplPtr = boost::intrusive_ptr<SynchroImpl>;
+  using SynchroImplPtr = boost::intrusive_ptr<SynchroImpl>;
   class SemaphoreImpl;
   using SemaphoreImplPtr = boost::intrusive_ptr<SemaphoreImpl>;
   XBT_PUBLIC void intrusive_ptr_add_ref(SemaphoreImpl* sem);
index fa2c811..96d19d8 100644 (file)
@@ -120,7 +120,7 @@ void ActivityImpl::wait_for(actor::ActorImpl* issuer, double timeout)
       else
         comm->dst_timeout_ = sleep;
     } else {
-      RawImplPtr synchro(new SynchroImpl([this, issuer]() {
+      SynchroImplPtr synchro(new SynchroImpl([this, issuer]() {
         this->unregister_simcall(&issuer->simcall_);
         issuer->waiting_synchro_ = nullptr;
         issuer->exception_       = nullptr;
index 7acbe2b..6da6349 100644 (file)
@@ -90,6 +90,7 @@ public:
   // Support for the boost::intrusive_ptr<ActivityImpl> datatype
   friend XBT_PUBLIC void intrusive_ptr_add_ref(ActivityImpl* activity);
   friend XBT_PUBLIC void intrusive_ptr_release(ActivityImpl* activity);
+  int get_refcount() { return refcount_; } // For debugging purpose
 
   static xbt::signal<void(ActivityImpl const&)> on_suspended;
   static xbt::signal<void(ActivityImpl const&)> on_resumed;
index 3cdfa9c..d38532a 100644 (file)
@@ -39,7 +39,7 @@ void ConditionVariableImpl::signal()
     smx_simcall_t simcall = &proc.simcall_;
     const auto* observer  = dynamic_cast<kernel::actor::ConditionWaitSimcall*>(simcall->observer_);
     xbt_assert(observer != nullptr);
-    observer->get_mutex()->lock(simcall->issuer_);
+    observer->get_mutex()->lock_async(simcall->issuer_)->wait_for(simcall->issuer_, -1);
   }
   XBT_OUT();
 }
@@ -73,7 +73,7 @@ void ConditionVariableImpl::wait(smx_mutex_t mutex, double timeout, actor::Actor
     mutex->unlock(issuer);
   }
 
-  RawImplPtr synchro(new SynchroImpl([this, issuer]() {
+  SynchroImplPtr synchro(new SynchroImpl([this, issuer]() {
     this->remove_sleeping_actor(*issuer);
     auto* observer = dynamic_cast<kernel::actor::ConditionWaitSimcall*>(issuer->simcall_.observer_);
     xbt_assert(observer != nullptr);
index 2e21728..5087f66 100644 (file)
@@ -22,25 +22,50 @@ namespace simgrid {
 namespace kernel {
 namespace activity {
 
-void MutexImpl::lock(actor::ActorImpl* issuer)
+bool MutexAcquisitionImpl::test(actor::ActorImpl*)
 {
-  XBT_IN("(%p; %p)", this, issuer);
-  MC_CHECK_NO_DPOR();
+  return mutex_->owner_ == issuer_;
+}
+void MutexAcquisitionImpl::wait_for(actor::ActorImpl* issuer, double timeout)
+{
+  xbt_assert(mutex_->locked_); // it was locked either by someone else or by me during the lock_async
+  xbt_assert(
+      issuer == issuer_,
+      "Actors can only wait acquisitions that they created themselves while this one was created by actor id %ld.",
+      issuer_->get_pid());
+  xbt_assert(timeout < 0, "Timeouts on mutex acquisitions are not implemented yet.");
+
+  this->register_simcall(&issuer_->simcall_); // Block on that acquisition
+
+  if (mutex_->get_owner() == issuer_) { // I'm the owner
+    finish();
+  } else {
+    // Already in the queue
+  }
+}
+void MutexAcquisitionImpl::finish()
+{
+  xbt_assert(simcalls_.size() == 1, "Unexpected number of simcalls waiting: %zu", simcalls_.size());
+  smx_simcall_t simcall = simcalls_.front();
+  simcalls_.pop_front();
+
+  simcall->issuer_->waiting_synchro_ = nullptr;
+  simcall->issuer_->simcall_answer();
+}
+
+MutexAcquisitionImplPtr MutexImpl::lock_async(actor::ActorImpl* issuer)
+{
+  auto res = MutexAcquisitionImplPtr(new kernel::activity::MutexAcquisitionImpl(issuer, this), true);
 
   if (locked_) {
     /* FIXME: check if the host is active ? */
     /* Somebody using the mutex, use a synchronization to get host failures */
-    RawImplPtr synchro(new SynchroImpl([this, issuer]() { this->remove_sleeping_actor(*issuer); }));
-    (*synchro).set_host(issuer->get_host()).start();
-    synchro->register_simcall(&issuer->simcall_);
-    sleeping_.push_back(*issuer);
+    sleeping_.push_back(res);
   } else {
-    /* mutex free */
     locked_ = true;
     owner_  = issuer;
-    issuer->simcall_answer();
   }
-  XBT_OUT();
+  return res;
 }
 
 /** Tries to lock the mutex for a actor
@@ -78,10 +103,13 @@ void MutexImpl::unlock(actor::ActorImpl* issuer)
 
   if (not sleeping_.empty()) {
     /* Give the ownership to the first waiting actor */
-    owner_ = &sleeping_.front();
+    auto acq = sleeping_.front();
+    owner_   = acq->get_issuer();
+
+    if (acq == owner_->waiting_synchro_)
+      acq->finish();
+
     sleeping_.pop_front();
-    owner_->waiting_synchro_ = nullptr;
-    owner_->simcall_answer();
   } else {
     /* nobody to wake up */
     locked_ = false;
index a88b74e..5f9e27d 100644 (file)
@@ -7,6 +7,7 @@
 #define SIMGRID_KERNEL_ACTIVITY_MUTEX_HPP
 
 #include "simgrid/s4u/Mutex.hpp"
+#include "src/kernel/activity/ActivityImpl.hpp"
 #include "src/kernel/actor/ActorImpl.hpp"
 #include <boost/intrusive/list.hpp>
 
@@ -14,20 +15,69 @@ namespace simgrid {
 namespace kernel {
 namespace activity {
 
+/** Mutex Acquisition: the act / process of acquiring the mutex.
+ *
+ * You can declare some interest on a mutex without being blocked waiting if it's already occupied.
+ * If it gets freed by its current owned, you become the new owner, even if you're still not blocked on it.
+ * Nobody can lock it behind your back or overpass you in the queue in any way, even if you're still not blocked on it.
+ *
+ * Afterward, when you do consider the lock, the test() or wait() operations are both non-blocking since you're the
+ * owner. People who declared interest in the mutex after you get stuck in the queue behind you.
+ *
+ *
+ * Splitting the locking process this way is interesting for symmetry with the other activities such as exec or
+ * communication that do have an async variant and could be mildly interesting to the users once exposed in S4U, but
+ * that's not the only reason. It's also very important to the MC world: the Mutex::lock_async() is always enabled
+ * (nothing can prevent you from adding yourself to the queue of potential owners) while Acquisition::wait() is
+ * persistent: it's not always enabled but once it gets enabled (because you're the owner), it remains enabled for ever.
+ *
+ * Mutex::lock() is not persistent: sometimes it's enabled if the mutex is free, and then it gets disabled if
+ * someone else locks the mutex, and then it becomes enabled again once the mutex is freed. This is why Mutex::lock()
+ * is not used in our MC computational model: we ban non-persistent transitions because they would make some
+ * computations much more complex.
+ *
+ * In particular, computing the extension of an unfolding's configuration is polynomial when you only have persistent
+ * transitions while it's O(2^n) when some of the transitions are non-persistent (you have to consider again all subsets
+ * of a set if some transitions may become disabled in between, while you don't have to reconsider them if you can reuse
+ * your previous computations).
+ */
+class XBT_PUBLIC MutexAcquisitionImpl
+    : public ActivityImpl_T<MutexAcquisitionImpl> { // Acquisition: n. The act or process of acquiring.
+  actor::ActorImpl* issuer_ = nullptr;
+  MutexImpl* mutex_         = nullptr;
+
+public:
+  MutexAcquisitionImpl(actor::ActorImpl* issuer, MutexImpl* mutex) : issuer_(issuer), mutex_(mutex) {}
+  MutexImplPtr get_mutex() { return mutex_; }
+  actor::ActorImpl* get_issuer() { return issuer_; }
+
+  bool test(actor::ActorImpl* issuer = nullptr) override;
+  void wait_for(actor::ActorImpl* issuer, double timeout) override;
+  void post() override
+  { /*no surf action*/
+  }
+  void finish() override;
+  void set_exception(actor::ActorImpl* issuer) override
+  { /* nothing to do */
+  }
+};
+
 class XBT_PUBLIC MutexImpl {
   std::atomic_int_fast32_t refcount_{1};
   s4u::Mutex piface_;
   bool locked_ = false;
   actor::ActorImpl* owner_ = nullptr;
   // List of sleeping actors:
-  actor::SynchroList sleeping_;
+  std::deque<MutexAcquisitionImplPtr> sleeping_;
+
+  friend MutexAcquisitionImpl;
 
 public:
   MutexImpl() : piface_(this) {}
   MutexImpl(MutexImpl const&) = delete;
   MutexImpl& operator=(MutexImpl const&) = delete;
 
-  void lock(actor::ActorImpl* issuer);
+  MutexAcquisitionImplPtr lock_async(actor::ActorImpl* issuer);
   bool try_lock(actor::ActorImpl* issuer);
   void unlock(actor::ActorImpl* issuer);
   bool is_locked() const { return locked_; }
@@ -35,7 +85,6 @@ public:
   MutexImpl* ref();
   void unref();
 
-  void remove_sleeping_actor(actor::ActorImpl& actor) { xbt::intrusive_erase(sleeping_, actor); }
   actor::ActorImpl* get_owner() const { return owner_; }
 
   // boost::intrusive_ptr<Mutex> support:
index 7d9bfab..85c1edf 100644 (file)
@@ -20,7 +20,7 @@ void SemaphoreImpl::acquire(actor::ActorImpl* issuer, double timeout)
   xbt_assert(std::isfinite(timeout), "timeout is not finite!");
 
   if (value_ <= 0) {
-    RawImplPtr synchro(new SynchroImpl([this, issuer]() {
+    SynchroImplPtr synchro(new SynchroImpl([this, issuer]() {
       this->remove_sleeping_actor(*issuer);
       auto* observer = dynamic_cast<kernel::actor::SemAcquireSimcall*>(issuer->simcall_.observer_);
       xbt_assert(observer != nullptr);
index ccb7df9..fbf4d98 100644 (file)
@@ -6,7 +6,6 @@
 #include "simgrid/s4u/Host.hpp"
 #include "src/kernel/activity/CommImpl.hpp"
 #include "src/kernel/activity/MailboxImpl.hpp"
-#include "src/kernel/activity/MutexImpl.hpp"
 #include "src/kernel/actor/ActorImpl.hpp"
 #include "src/kernel/actor/SimcallObserver.hpp"
 #include "src/mc/mc_config.hpp"
diff --git a/src/kernel/actor/MutexObserver.cpp b/src/kernel/actor/MutexObserver.cpp
new file mode 100644 (file)
index 0000000..37902a0
--- /dev/null
@@ -0,0 +1,64 @@
+/* Copyright (c) 2019-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/kernel/actor/MutexObserver.hpp"
+#include "simgrid/s4u/Host.hpp"
+#include "src/kernel/activity/MutexImpl.hpp"
+#include "src/kernel/actor/ActorImpl.hpp"
+#include "src/mc/mc_config.hpp"
+
+#include <sstream>
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(obs_mutex, mc_observer, "Logging specific to mutex simcalls observation");
+
+namespace simgrid {
+namespace kernel {
+namespace actor {
+
+#if 0
+bool MutexSimcall::depends(SimcallObserver* other)
+{
+  if (dynamic_cast<RandomSimcall*>(other) != nullptr)
+    return other->depends(this); /* Other is random, that is very permissive. Use that relation instead. */
+
+#if 0 /* This code is currently broken and shouldn't be used. We must implement asynchronous locks before */
+  MutexSimcall* that = dynamic_cast<MutexSimcall*>(other);
+  if (that == nullptr)
+    return true; // Depends on anything we don't know
+
+  /* Theorem 4.4.7: Any pair of synchronization actions of distinct actors concerning distinct mutexes are independent */
+  if (this->get_issuer() != that->get_issuer() && this->get_mutex() != that->get_mutex())
+    return false;
+
+  /* Theorem 4.4.8 An AsyncMutexLock is independent with a MutexUnlock of another actor */
+  if (((dynamic_cast<MutexLockSimcall*>(this) != nullptr && dynamic_cast<MutexUnlockSimcall*>(that)) ||
+       (dynamic_cast<MutexLockSimcall*>(that) != nullptr && dynamic_cast<MutexUnlockSimcall*>(this))) &&
+      get_issuer() != other->get_issuer())
+    return false;
+#endif
+  return true; // Depend on things we don't know for sure that they are independent
+}
+#endif
+
+MutexObserver::MutexObserver(ActorImpl* actor, activity::MutexImpl* mutex) : SimcallObserver(actor), mutex_(mutex) {}
+MutexTestObserver::MutexTestObserver(ActorImpl* actor, activity::MutexImpl* mutex) : MutexObserver(actor, mutex) {}
+
+MutexLockAsyncObserver::MutexLockAsyncObserver(ActorImpl* actor, activity::MutexImpl* mutex)
+    : MutexObserver(actor, mutex)
+{
+}
+MutexLockWaitObserver::MutexLockWaitObserver(ActorImpl* actor, activity::MutexAcquisitionImplPtr synchro)
+    : MutexObserver(actor, synchro->get_mutex().get()), synchro_(synchro)
+{
+}
+
+bool MutexLockWaitObserver::is_enabled()
+{
+  return synchro_->test();
+}
+
+} // namespace actor
+} // namespace kernel
+} // namespace simgrid
diff --git a/src/kernel/actor/MutexObserver.hpp b/src/kernel/actor/MutexObserver.hpp
new file mode 100644 (file)
index 0000000..bb83761
--- /dev/null
@@ -0,0 +1,56 @@
+/* Copyright (c) 2019-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_MUTEX_OBSERVER_HPP
+#define SIMGRID_MC_MUTEX_OBSERVER_HPP
+
+#include "simgrid/forward.h"
+#include "src/kernel/activity/MutexImpl.hpp"
+#include "src/kernel/actor/ActorImpl.hpp"
+#include "src/kernel/actor/SimcallObserver.hpp"
+
+#include <string>
+
+namespace simgrid {
+namespace kernel {
+namespace actor {
+
+/* abstract */
+class MutexObserver : public SimcallObserver {
+  activity::MutexImpl* const mutex_;
+
+public:
+  MutexObserver(ActorImpl* actor, activity::MutexImpl* mutex);
+  virtual ~MutexObserver() = default;
+  activity::MutexImpl* get_mutex() const { return mutex_; }
+};
+
+class MutexTestObserver : public MutexObserver {
+public:
+  MutexTestObserver(ActorImpl* actor, activity::MutexImpl* mutex);
+};
+
+class MutexLockAsyncObserver : public MutexObserver {
+public:
+  MutexLockAsyncObserver(ActorImpl* actor, activity::MutexImpl* mutex);
+};
+
+class MutexLockWaitObserver : public MutexObserver {
+  activity::MutexAcquisitionImplPtr synchro_;
+
+public:
+  MutexLockWaitObserver(ActorImpl* actor, activity::MutexAcquisitionImplPtr synchro);
+  bool is_enabled() override;
+};
+
+class MutexUnlockObserver : public MutexObserver {
+  using MutexObserver::MutexObserver;
+};
+
+} // namespace actor
+} // namespace kernel
+} // namespace simgrid
+
+#endif
index 3809e1a..80d8326 100644 (file)
@@ -7,7 +7,6 @@
 #include "simgrid/s4u/Host.hpp"
 #include "src/kernel/activity/CommImpl.hpp"
 #include "src/kernel/activity/MailboxImpl.hpp"
-#include "src/kernel/activity/MutexImpl.hpp"
 #include "src/kernel/actor/ActorImpl.hpp"
 #include "src/mc/mc_config.hpp"
 
@@ -38,29 +37,6 @@ void RandomSimcall::serialize(std::stringstream& stream) const
   stream << min_ << ' ' << max_;
 }
 
-bool MutexSimcall::depends(SimcallObserver* other)
-{
-  if (dynamic_cast<RandomSimcall*>(other) != nullptr)
-    return other->depends(this); /* Other is random, that is very permissive. Use that relation instead. */
-
-#if 0 /* This code is currently broken and shouldn't be used. We must implement asynchronous locks before */
-  MutexSimcall* that = dynamic_cast<MutexSimcall*>(other);
-  if (that == nullptr)
-    return true; // Depends on anything we don't know
-
-  /* Theorem 4.4.7: Any pair of synchronization actions of distinct actors concerning distinct mutexes are independent */
-  if (this->get_issuer() != that->get_issuer() && this->get_mutex() != that->get_mutex())
-    return false;
-
-  /* Theorem 4.4.8 An AsyncMutexLock is independent with a MutexUnlock of another actor */
-  if (((dynamic_cast<MutexLockSimcall*>(this) != nullptr && dynamic_cast<MutexUnlockSimcall*>(that)) ||
-       (dynamic_cast<MutexLockSimcall*>(that) != nullptr && dynamic_cast<MutexUnlockSimcall*>(this))) &&
-      get_issuer() != other->get_issuer())
-    return false;
-#endif
-  return true; // Depend on things we don't know for sure that they are independent
-}
-
 void RandomSimcall::prepare(int times_considered)
 {
   next_value_ = min_ + times_considered;
@@ -72,22 +48,6 @@ int RandomSimcall::get_max_consider()
   return max_ - min_ + 1;
 }
 
-/*
-std::string MutexLockSimcall::to_string(int times_considered) const
-{
-  auto mutex      = get_mutex();
-  std::string res = SimcallObserver::to_string(times_considered) + (blocking_ ? "Mutex LOCK" : "Mutex TRYLOCK");
-  res += "(locked = " + std::to_string(mutex->is_locked());
-  res += ", owner = " + std::to_string(mutex->get_owner() ? mutex->get_owner()->get_pid() : -1);
-  res += ", sleeping = n/a)";
-  return res;
-}*/
-
-bool MutexLockSimcall::is_enabled()
-{
-  return not blocking_ || get_mutex()->get_owner() == nullptr || get_mutex()->get_owner() == get_issuer();
-}
-
 bool ConditionWaitSimcall::is_enabled()
 {
   static bool warned = false;
index 0bba980..ed9a500 100644 (file)
@@ -89,30 +89,6 @@ public:
   bool depends(SimcallObserver* other) override;
 };
 
-class MutexSimcall : public SimcallObserver {
-  activity::MutexImpl* const mutex_;
-
-public:
-  MutexSimcall(ActorImpl* actor, activity::MutexImpl* mutex) : SimcallObserver(actor), mutex_(mutex) {}
-  activity::MutexImpl* get_mutex() const { return mutex_; }
-  bool depends(SimcallObserver* other) override;
-};
-
-class MutexUnlockSimcall : public MutexSimcall {
-  using MutexSimcall::MutexSimcall;
-};
-
-class MutexLockSimcall : public MutexSimcall {
-  const bool blocking_;
-
-public:
-  MutexLockSimcall(ActorImpl* actor, activity::MutexImpl* mutex, bool blocking = true)
-      : MutexSimcall(actor, mutex), blocking_(blocking)
-  {
-  }
-  bool is_enabled() override;
-};
-
 class ConditionWaitSimcall : public ResultingSimcall<bool> {
   activity::ConditionVariableImpl* const cond_;
   activity::MutexImpl* const mutex_;
index 1ce93e0..783b6c8 100644 (file)
@@ -3,10 +3,12 @@
 /* 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 <simgrid/modelchecker.h>
 #include <simgrid/mutex.h>
 #include <simgrid/s4u/Mutex.hpp>
 #include <src/kernel/activity/MutexImpl.hpp>
-#include <src/kernel/actor/SimcallObserver.hpp>
+#include <src/kernel/actor/MutexObserver.hpp>
+#include <src/mc/mc_replay.hpp>
 
 namespace simgrid {
 namespace s4u {
@@ -15,8 +17,18 @@ namespace s4u {
 void Mutex::lock()
 {
   kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
-  kernel::actor::MutexLockSimcall observer{issuer, pimpl_};
-  kernel::actor::simcall_blocking([&observer] { observer.get_mutex()->lock(observer.get_issuer()); }, &observer);
+
+  if (MC_is_active() || MC_record_replay_is_active()) { // Split in 2 simcalls for transition persistency
+    kernel::actor::MutexLockAsyncObserver lock_observer{issuer, pimpl_};
+    auto acquisition = kernel::actor::simcall([issuer, this] { return pimpl_->lock_async(issuer); }, &lock_observer);
+
+    kernel::actor::MutexLockWaitObserver wait_observer{issuer, acquisition};
+    kernel::actor::simcall_blocking([issuer, acquisition] { return acquisition->wait_for(issuer, -1); },
+                                    &wait_observer);
+
+  } else { // Do it in one simcall only
+    kernel::actor::simcall_blocking([issuer, this] { pimpl_->lock_async(issuer)->wait_for(issuer, -1); });
+  }
 }
 
 /** @brief Release the ownership of the mutex, unleashing a blocked actor (if any)
@@ -26,7 +38,7 @@ void Mutex::lock()
 void Mutex::unlock()
 {
   kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
-  kernel::actor::MutexUnlockSimcall observer{issuer, pimpl_};
+  kernel::actor::MutexUnlockObserver observer{issuer, pimpl_};
   kernel::actor::simcall([this, issuer] { this->pimpl_->unlock(issuer); }, &observer);
 }
 
@@ -34,7 +46,7 @@ void Mutex::unlock()
 bool Mutex::try_lock()
 {
   kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
-  kernel::actor::MutexLockSimcall observer{issuer, pimpl_, false};
+  kernel::actor::MutexTestObserver observer{issuer, pimpl_};
   return kernel::actor::simcall([&observer] { return observer.get_mutex()->try_lock(observer.get_issuer()); },
                                 &observer);
 }
index 9750bf5..3a18f94 100644 (file)
@@ -415,6 +415,8 @@ set(SIMIX_SRC
   src/kernel/actor/ActorImpl.hpp
   src/kernel/actor/CommObserver.cpp
   src/kernel/actor/CommObserver.hpp
+  src/kernel/actor/MutexObserver.cpp
+  src/kernel/actor/MutexObserver.hpp
   src/kernel/actor/SimcallObserver.cpp
   src/kernel/actor/SimcallObserver.hpp