Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Various sonar cleanups
authorMartin Quinson <martin.quinson@ens-rennes.fr>
Tue, 21 Nov 2023 13:53:20 +0000 (14:53 +0100)
committerMartin Quinson <martin.quinson@ens-rennes.fr>
Tue, 21 Nov 2023 13:53:20 +0000 (14:53 +0100)
24 files changed:
examples/python/comm-ready/comm-ready.py
examples/sthread/pthread-mutex-recursive.c
include/simgrid/plugins/battery.hpp
include/simgrid/plugins/chiller.hpp
include/simgrid/s4u/Engine.hpp
include/simgrid/s4u/NetZone.hpp
include/simgrid/s4u/Task.hpp
src/bindings/python/simgrid_python.cpp
src/kernel/activity/MutexImpl.hpp
src/kernel/actor/CommObserver.cpp
src/kernel/actor/SimcallObserver.hpp
src/mc/api/State.cpp
src/mc/api/strategy/BasicStrategy.hpp
src/mc/explo/DFSExplorer.cpp
src/mc/transition/TransitionActor.cpp
src/mc/transition/TransitionAny.cpp
src/mc/transition/TransitionComm.cpp
src/mc/transition/TransitionObjectAccess.cpp
src/mc/transition/TransitionRandom.cpp
src/plugins/battery.cpp
src/plugins/chiller.cpp
src/s4u/s4u_ActivitySet.cpp
src/smpi/bindings/smpi_pmpi_request.cpp
src/sthread/sthread.c

index f874bd9..2006532 100644 (file)
@@ -58,7 +58,7 @@ def peer(my_id: int, message_count: int, payload_size: int, peers_count: int):
             start = Engine.clock
             received: str = my_mailbox.get()
             waiting_time = Engine.clock - start
-            if waiting_time != 0.0:
+            if waiting_time > 0.0:
                 raise AssertionError(f"Expecting the waiting time to be 0.0 because the communication was supposedly "
                                      f"ready, but got {waiting_time} instead")
             this_actor.info(f"I got a '{received}'.")
index 482cf3e..63c9ccc 100644 (file)
@@ -40,7 +40,8 @@ static void* thread_function(void* arg)
 
 int main()
 {
-  pthread_t thread1, thread2;
+  pthread_t thread1;
+  pthread_t thread2;
   pthread_mutex_t mutex_dflt = PTHREAD_MUTEX_INITIALIZER; // Non-recursive mutex
 
   pthread_mutexattr_t attr;
index 61937a9..fc39505 100644 (file)
@@ -105,7 +105,7 @@ private:
   double energy_consumed_j_ = 0;
   double last_updated_      = 0;
 
-  explicit Battery();
+  explicit Battery() = default;
   explicit Battery(const std::string& name, double state_of_charge, double nominal_charge_power_w,
                    double nominal_discharge_power_w, double charge_efficiency, double discharge_efficiency,
                    double initial_capacity_wh, int cycles);
@@ -133,7 +133,7 @@ public:
   void set_load(const std::string& name, double power_w);
   void set_load(const std::string& name, bool active);
   void connect_host(s4u::Host* host, bool active = true);
-  std::string get_name() {return name_;}
+  std::string get_name() const { return name_; }
   double get_state_of_charge();
   double get_state_of_health();
   double get_capacity();
index 11fa173..78d1db0 100644 (file)
@@ -100,7 +100,7 @@ public:
   double get_temp_in() { return temp_in_c_; }
   double get_power() { return power_w_; }
   double get_energy_consumed() { return energy_consumed_j_; }
-  double get_time_to_goal_temp();
+  double get_time_to_goal_temp() const;
 };
 
 } // namespace simgrid::plugins
index fbef8cc..2bdb4a9 100644 (file)
@@ -93,8 +93,8 @@ public:
   /** @verbatim embed:rst:inline Bind an actor name that could be found in :ref:`pf_tag_actor` tag to a class name passed as a template parameter. See the :ref:`example <s4u_ex_actors_create>`. @endverbatim */
   template <class F> void register_actor(const std::string& name)
   {
-    kernel::actor::ActorCodeFactory code_factory = [](std::vector<std::string> args) {
-      return kernel::actor::ActorCode([args = std::move(args)]() mutable {
+    kernel::actor::ActorCodeFactory code_factory = [](std::vector<std::string> args_factory) {
+      return kernel::actor::ActorCode([args = std::move(args_factory)]() mutable {
         F code(std::move(args));
         code();
       });
@@ -104,8 +104,8 @@ public:
   /** @verbatim embed:rst:inline Bind an actor name that could be found in :ref:`pf_tag_actor` tag to a function name passed as a parameter. See the :ref:`example <s4u_ex_actors_create>`. @endverbatim */
   template <class F> void register_actor(const std::string& name, F code)
   {
-    kernel::actor::ActorCodeFactory code_factory = [code](std::vector<std::string> args) {
-      return kernel::actor::ActorCode([code, args = std::move(args)]() mutable { code(std::move(args)); });
+    kernel::actor::ActorCodeFactory code_factory = [code](std::vector<std::string> args_factory) {
+      return kernel::actor::ActorCode([code, args = std::move(args_factory)]() mutable { code(std::move(args)); });
     };
     register_function(name, code_factory);
   }
index 76125f3..ab535fa 100644 (file)
@@ -62,7 +62,7 @@ public:
   /** @brief Get the gateway associated to this netzone */
   kernel::routing::NetPoint* get_gateway() const;
   kernel::routing::NetPoint* get_gateway(const std::string& name) const;
-  void set_gateway(s4u::Host* router) { set_gateway(router->get_netpoint()); }
+  void set_gateway(const s4u::Host* router) { set_gateway(router->get_netpoint()); }
   void set_gateway(kernel::routing::NetPoint* router);
   void set_gateway(const std::string& name, kernel::routing::NetPoint* router);
 
index 03ee265..f10729b 100644 (file)
@@ -64,7 +64,7 @@ protected:
   virtual void fire(std::string instance);
   void complete(std::string instance);
 
-  void store_activity(ActivityPtr a, std::string instance) { current_activities_[instance].push_back(a); }
+  void store_activity(ActivityPtr a, const std::string& instance) { current_activities_[instance].push_back(a); }
 
   virtual void add_instances(int n);
   virtual void remove_instances(int n);
index 41e8646..7f5f6b9 100644 (file)
@@ -294,7 +294,7 @@ PYBIND11_MODULE(simgrid, m)
       .def("create_router", &simgrid::s4u::NetZone::create_router, "Create a router")
       .def("set_parent", &simgrid::s4u::NetZone::set_parent, "Set the parent of this zone")
       .def("set_property", &simgrid::s4u::NetZone::set_property, "Add a property to this zone")
-      .def("set_gateway", py::overload_cast<simgrid::s4u::Host*>(&simgrid::s4u::NetZone::set_gateway),
+      .def("set_gateway", py::overload_cast<const simgrid::s4u::Host*>(&simgrid::s4u::NetZone::set_gateway),
            "Specify the gateway of this zone, to be used for inter-zone routes")
       .def("set_gateway", py::overload_cast<simgrid::kernel::routing::NetPoint*>(&simgrid::s4u::NetZone::set_gateway),
            "Specify the gateway of this zone, to be used for inter-zone routes")
index 75cb5d6..8bf71be 100644 (file)
@@ -52,10 +52,10 @@ class XBT_PUBLIC MutexAcquisitionImpl : public ActivityImpl_T<MutexAcquisitionIm
 
 public:
   MutexAcquisitionImpl(actor::ActorImpl* issuer, MutexImpl* mutex) : issuer_(issuer), mutex_(mutex) {}
-  MutexImplPtr get_mutex() { return mutex_; }
-  actor::ActorImpl* get_issuer() { return issuer_; }
+  MutexImplPtr get_mutex() const { return mutex_; }
+  actor::ActorImpl* get_issuer() const { return issuer_; }
   void grant() { granted_ = true; }
-  bool is_granted() { return granted_; }
+  bool is_granted() const { return granted_; }
 
   bool test(actor::ActorImpl* issuer = nullptr) override;
   void wait_for(actor::ActorImpl* issuer, double timeout) override;
@@ -78,7 +78,7 @@ class XBT_PUBLIC MutexImpl {
   friend MutexAcquisitionImpl;
 
 public:
-  MutexImpl(bool recursive = false) : piface_(this), is_recursive_(recursive) {}
+  explicit MutexImpl(bool recursive = false) : piface_(this), is_recursive_(recursive) {}
   MutexImpl(MutexImpl const&) = delete;
   MutexImpl& operator=(MutexImpl const&) = delete;
 
index d860c8c..a7257d7 100644 (file)
@@ -222,8 +222,8 @@ void CommIsendSimcall::serialize(std::stringstream& stream) const
 }
 std::string CommIsendSimcall::to_string() const
 {
-  return "CommAsyncSend(comm_id: " + std::to_string((comm_ ? comm_->get_id() : 0)) + " mbox:" +
-         std::to_string(mbox_->get_id()) + " tag: " + std::to_string(tag_) + ")";
+  return "CommAsyncSend(comm_id: " + std::to_string(comm_ ? comm_->get_id() : 0) +
+         " mbox:" + std::to_string(mbox_->get_id()) + " tag: " + std::to_string(tag_) + ")";
 }
 
 void CommIrecvSimcall::serialize(std::stringstream& stream) const
@@ -237,8 +237,8 @@ void CommIrecvSimcall::serialize(std::stringstream& stream) const
 
 std::string CommIrecvSimcall::to_string() const
 {
-  return "CommAsyncRecv(comm_id: " + std::to_string((comm_ ? comm_->get_id() : 0)) + " mbox:" +
-         std::to_string(mbox_->get_id()) + " tag: " + std::to_string(tag_) + ")";
+  return "CommAsyncRecv(comm_id: " + std::to_string(comm_ ? comm_->get_id() : 0) +
+         " mbox:" + std::to_string(mbox_->get_id()) + " tag: " + std::to_string(tag_) + ")";
 }
 
 void MessIputSimcall::serialize(std::stringstream& stream) const
index c7d1353..de3f4fc 100644 (file)
@@ -111,7 +111,7 @@ public:
 class ActorSleepSimcall final : public SimcallObserver {
 
 public:
-  ActorSleepSimcall(ActorImpl* actor) : SimcallObserver(actor) {}
+  explicit ActorSleepSimcall(ActorImpl* actor) : SimcallObserver(actor) {}
   void serialize(std::stringstream& stream) const override;
   std::string to_string() const override;
 };
index 52ffde6..f537a48 100644 (file)
@@ -245,7 +245,7 @@ void State::sprout_tree_from_parent_state()
               "to schedule from the wakeup tree? Trace so far:",
               get_transition_in()->to_string(false).c_str(), get_transition_in()->aid_,
               min_process_node.value()->get_action()->to_string(false).c_str(), min_process_node.value()->get_actor());
-    for (auto elm : Exploration::get_instance()->get_textual_trace())
+    for (auto const& elm : Exploration::get_instance()->get_textual_trace())
       XBT_ERROR("%s", elm.c_str());
     xbt_abort();
   }
index 3d7d01b..ca44509 100644 (file)
@@ -31,7 +31,7 @@ public:
                  "--cfg=model-check/max-depth. Here are the 100 first trace elements",
                  _sg_mc_max_depth.get());
       auto trace = Exploration::get_instance()->get_textual_trace(100);
-      for (auto elm : trace)
+      for (auto const& elm : trace)
         XBT_CERROR(mc_dfs, "  %s", elm.c_str());
       xbt_die("Aborting now.");
     }
index 0466d66..b328d15 100644 (file)
@@ -433,7 +433,7 @@ void DFSExplorer::backtrack()
 
   // Search how to restore the backtracking point
   std::deque<Transition*> replay_recipe;
-  for (auto* s = backtracking_point.get(); s != nullptr; s = s->get_parent_state().get()) {
+  for (const auto* s = backtracking_point.get(); s != nullptr; s = s->get_parent_state().get()) {
     if (s->get_transition_in() != nullptr) // The root has no transition_in
       replay_recipe.push_front(s->get_transition_in().get());
   }
index 16a17a3..3e1027b 100644 (file)
@@ -49,18 +49,14 @@ bool ActorJoinTransition::depends(const Transition* other) const
 
 bool ActorJoinTransition::reversible_race(const Transition* other) const
 {
-  switch (type_) {
-    case Type::ACTOR_JOIN:
-      // ActorJoin races with another event iff its target `T` is the same as
-      // the actor executing the other transition. Clearly, then, we could not join
-      // on that actor `T` and then run a transition by `T`, so no race is reversible
-      return false;
-    default:
-      xbt_die("Unexpected transition type %s", to_c_str(type_));
-  }
+  xbt_assert(type_ == Type::ACTOR_JOIN, "Unexpected transition type %s", to_c_str(type_));
+
+  // ActorJoin races with another event iff its target `T` is the same as  the actor executing the other transition.
+  // Clearly, then, we could not join on that actor `T` and then run a transition by `T`, so no race is reversible
+  return false;
 }
 
-ActorSleepTransition::ActorSleepTransition(aid_t issuer, int times_considered, std::stringstream& stream)
+ActorSleepTransition::ActorSleepTransition(aid_t issuer, int times_considered, std::stringstream&)
     : Transition(Type::ACTOR_SLEEP, issuer, times_considered)
 {
   XBT_DEBUG("ActorSleepTransition()");
@@ -81,12 +77,9 @@ bool ActorSleepTransition::depends(const Transition* other) const
 
 bool ActorSleepTransition::reversible_race(const Transition* other) const
 {
-  switch (type_) {
-    case Type::ACTOR_SLEEP:
-      return true; // Always enabled
-    default:
-      xbt_die("Unexpected transition type %s", to_c_str(type_));
-  }
+  xbt_assert(type_ == Type::ACTOR_SLEEP, "Unexpected transition type %s", to_c_str(type_));
+
+  return true; // Always enabled
 }
 
 } // namespace simgrid::mc
index 580fb44..b3c7b63 100644 (file)
@@ -45,12 +45,9 @@ bool TestAnyTransition::depends(const Transition* other) const
 }
 bool TestAnyTransition::reversible_race(const Transition* other) const
 {
-  switch (type_) {
-    case Type::TESTANY:
-      return true; // TestAny is always enabled
-    default:
-      xbt_die("Unexpected transition type %s", to_c_str(type_));
-  }
+  xbt_assert(type_ == Type::TESTANY, "Unexpected transition type %s", to_c_str(type_));
+
+  return true; // TestAny is always enabled
 }
 
 WaitAnyTransition::WaitAnyTransition(aid_t issuer, int times_considered, std::stringstream& stream)
@@ -81,13 +78,10 @@ bool WaitAnyTransition::depends(const Transition* other) const
 }
 bool WaitAnyTransition::reversible_race(const Transition* other) const
 {
-  switch (type_) {
-    case Type::WAITANY:
-      // TODO: We need to check if any of the transitions waited on occurred before `e1`
-      return true; // Let's overapproximate to not miss branches
-    default:
-      xbt_die("Unexpected transition type %s", to_c_str(type_));
-  }
+  xbt_assert(type_ == Type::WAITANY, "Unexpected transition type %s", to_c_str(type_));
+
+  // TODO: We need to check if any of the transitions waited on occurred before `e1`
+  return true; // Let's overapproximate to not miss branches
 }
 
 } // namespace simgrid::mc
index 19d8ebf..d23cd86 100644 (file)
@@ -59,13 +59,10 @@ bool CommWaitTransition::depends(const Transition* other) const
 
 bool CommWaitTransition::reversible_race(const Transition* other) const
 {
-  switch (type_) {
-    case Type::COMM_WAIT:
-      // If the other event is a communication event, then we are not reversible; otherwise we are reversible.
-      return other->type_ != Transition::Type::COMM_ASYNC_SEND && other->type_ != Transition::Type::COMM_ASYNC_RECV;
-    default:
-      xbt_die("Unexpected transition type %s", to_c_str(type_));
-  }
+  xbt_assert(type_ == Type::COMM_WAIT, "Unexpected transition type %s", to_c_str(type_));
+
+  // If the other event is a communication event, then we are not reversible; otherwise we are reversible.
+  return other->type_ != Transition::Type::COMM_ASYNC_SEND && other->type_ != Transition::Type::COMM_ASYNC_RECV;
 }
 
 CommTestTransition::CommTestTransition(aid_t issuer, int times_considered, unsigned comm_, aid_t sender_,
@@ -114,12 +111,8 @@ bool CommTestTransition::depends(const Transition* other) const
 
 bool CommTestTransition::reversible_race(const Transition* other) const
 {
-  switch (type_) {
-    case Type::COMM_TEST:
-      return true; // CommTest is always enabled
-    default:
-      xbt_die("Unexpected transition type %s", to_c_str(type_));
-  }
+  xbt_assert(type_ == Type::COMM_TEST, "Unexpected transition type %s", to_c_str(type_));
+  return true; // CommTest is always enabled
 }
 
 CommRecvTransition::CommRecvTransition(aid_t issuer, int times_considered, unsigned comm_, unsigned mbox_, int tag_)
@@ -189,12 +182,9 @@ bool CommRecvTransition::depends(const Transition* other) const
 
 bool CommRecvTransition::reversible_race(const Transition* other) const
 {
-  switch (type_) {
-    case Type::COMM_ASYNC_RECV:
-      return true; // CommRecv is always enabled
-    default:
-      xbt_die("Unexpected transition type %s", to_c_str(type_));
-  }
+  xbt_assert(type_ == Type::COMM_ASYNC_RECV, "Unexpected transition type %s", to_c_str(type_));
+
+  return true; // CommRecv is always enabled
 }
 
 CommSendTransition::CommSendTransition(aid_t issuer, int times_considered, unsigned comm_, unsigned mbox_, int tag_)
@@ -265,12 +255,9 @@ bool CommSendTransition::depends(const Transition* other) const
 
 bool CommSendTransition::reversible_race(const Transition* other) const
 {
-  switch (type_) {
-    case Type::COMM_ASYNC_SEND:
-      return true; // CommSend is always enabled
-    default:
-      xbt_die("Unexpected transition type %s", to_c_str(type_));
-  }
+  xbt_assert(type_ == Type::COMM_ASYNC_SEND, "Unexpected transition type %s", to_c_str(type_));
+
+  return true; // CommSend is always enabled
 }
 
 } // namespace simgrid::mc
index 33b4163..f32e459 100644 (file)
@@ -48,12 +48,9 @@ bool ObjectAccessTransition::depends(const Transition* o) const
 
 bool ObjectAccessTransition::reversible_race(const Transition* other) const
 {
-  switch (type_) {
-    case Type::OBJECT_ACCESS:
-      return true; // Object access is always enabled
-    default:
-      xbt_die("Unexpected transition type %s", to_c_str(type_));
-  }
+  xbt_assert(type_ == Type::OBJECT_ACCESS, "Unexpected transition type %s", to_c_str(type_));
+
+  return true; // Object access is always enabled
 }
 
 } // namespace simgrid::mc
index 81eab72..7470be2 100644 (file)
@@ -25,12 +25,9 @@ RandomTransition::RandomTransition(aid_t issuer, int times_considered, std::stri
 
 bool RandomTransition::reversible_race(const Transition* other) const
 {
-  switch (type_) {
-    case Type::RANDOM:
-      return true; // Random is always enabled
-    default:
-      xbt_die("Unexpected transition type %s", to_c_str(type_));
-  }
+  xbt_assert(type_ == Type::RANDOM, "Unexpected transition type %s", to_c_str(type_));
+
+  return true; // Random is always enabled
 }
 
 } // namespace simgrid::mc
index c682e17..0cbfdbc 100644 (file)
@@ -270,8 +270,6 @@ double Battery::next_occurring_handler()
   return time_delta;
 }
 
-Battery::Battery() {}
-
 Battery::Battery(const std::string& name, double state_of_charge, double nominal_charge_power_w,
                  double nominal_discharge_power_w, double charge_efficiency, double discharge_efficiency,
                  double initial_capacity_wh, int cycles)
index 7d2b9de..0a4d3af 100644 (file)
@@ -283,7 +283,7 @@ ChillerPtr Chiller::remove_host(s4u::Host* host)
 /** @ingroup plugin_chiller
  *  @return The time to reach to goal temp, assuming that the system remain in the same state.
  */
-double Chiller::get_time_to_goal_temp()
+double Chiller::get_time_to_goal_temp() const
 {
   if (goal_temp_c_ == temp_in_c_)
     return 0;
index 92a65ce..61957a3 100644 (file)
@@ -103,13 +103,13 @@ ActivityPtr ActivitySet::wait_any_for(double timeout)
     return ret;
   } catch (const HostFailureException& e) {
     handle_failed_activities();
-    throw e;
+    throw;
   } catch (const NetworkFailureException& e) {
     handle_failed_activities();
-    throw e;
+    throw;
   } catch (const StorageFailureException& e) {
     handle_failed_activities();
-    throw e;
+    throw;
   }
 }
 
index 73ea9b9..0dc9e32 100644 (file)
@@ -382,7 +382,7 @@ int PMPI_Sendrecv(const void* sendbuf, int sendcount, MPI_Datatype sendtype, int
   CHECK_BUFFER(1, sendbuf, sendcount, sendtype)
   CHECK_BUFFER(6, recvbuf, recvcount, recvtype)
   CHECK_ARGS(sendbuf == recvbuf && sendcount > 0 && recvcount > 0, MPI_ERR_BUFFER,
-             "%s: Invalid parameters 1 and 6: sendbuf and recvbuf must be disjoint", __func__);
+             "%s: Invalid parameters 1 and 6: sendbuf and recvbuf must be disjoint", __func__)
   CHECK_TAG(10, recvtag)
   CHECK_COMM(11)
   const SmpiBenchGuard suspend_bench;
@@ -443,7 +443,7 @@ int PMPI_Isendrecv(const void* sendbuf, int sendcount, MPI_Datatype sendtype, in
   CHECK_BUFFER(1, sendbuf, sendcount, sendtype)
   CHECK_BUFFER(6, recvbuf, recvcount, recvtype)
   CHECK_ARGS(sendbuf == recvbuf && sendcount > 0 && recvcount > 0, MPI_ERR_BUFFER,
-             "%s: Invalid parameters 1 and 6: sendbuf and recvbuf must be disjoint", __func__);
+             "%s: Invalid parameters 1 and 6: sendbuf and recvbuf must be disjoint", __func__)
   CHECK_TAG(10, recvtag)
   CHECK_COMM(11)
   CHECK_REQUEST(12)
index af26022..ad27e3f 100644 (file)
@@ -30,7 +30,7 @@ static int (*raw_pthread_mutex_destroy)(pthread_mutex_t*);
 
 static int (*raw_pthread_mutexattr_init)(pthread_mutexattr_t*);
 static int (*raw_pthread_mutexattr_settype)(pthread_mutexattr_t*, int);
-static int (*raw_pthread_mutexattr_gettype)(const pthread_mutexattr_t* restrict, int* restrict);
+static int (*raw_pthread_mutexattr_gettype)(const pthread_mutexattr_t*, int*);
 static int (*raw_pthread_mutexattr_getrobust)(const pthread_mutexattr_t*, int*);
 static int (*raw_pthread_mutexattr_setrobust)(pthread_mutexattr_t*, int);
 
@@ -125,12 +125,12 @@ void sthread_disable(void)
 intercepted_pthcall(mutexattr_init, (pthread_mutexattr_t * attr), (attr), ((sthread_mutexattr_t*)attr));
 intercepted_pthcall(mutexattr_settype, (pthread_mutexattr_t * attr, int type), (attr, type),
                     ((sthread_mutexattr_t*)attr, type));
-intercepted_pthcall(mutexattr_gettype, (const pthread_mutexattr_t* restrict attr, int* type), (attr, type),
+intercepted_pthcall(mutexattr_gettype, (const pthread_mutexattr_t* attr, int* type), (attr, type),
                     ((sthread_mutexattr_t*)attr, type));
-intercepted_pthcall(mutexattr_setrobust, (pthread_mutexattr_t* restrict attr, int robustness), (attr, robustness),
+intercepted_pthcall(mutexattr_setrobust, (pthread_mutexattr_t * attr, int robustness), (attr, robustness),
+                    ((sthread_mutexattr_t*)attr, robustness));
+intercepted_pthcall(mutexattr_getrobust, (const pthread_mutexattr_t* attr, int* robustness), (attr, robustness),
                     ((sthread_mutexattr_t*)attr, robustness));
-intercepted_pthcall(mutexattr_getrobust, (const pthread_mutexattr_t* restrict attr, int* restrict robustness),
-                    (attr, robustness), ((sthread_mutexattr_t*)attr, robustness));
 
 intercepted_pthcall(create, (pthread_t * thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg),
                     (thread, attr, start_routine, arg), ((sthread_t*)thread, attr, start_routine, arg));