Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'dev-get-hostname-faster' into 'master'
authorArnaud Giersch <arnaud.giersch@univ-fcomte.fr>
Thu, 30 Jun 2022 08:15:45 +0000 (08:15 +0000)
committerArnaud Giersch <arnaud.giersch@univ-fcomte.fr>
Thu, 30 Jun 2022 08:15:45 +0000 (08:15 +0000)
Make host_by_name faster

See merge request simgrid/simgrid!112

35 files changed:
ChangeLog
MANIFEST.in
docs/source/Installing_SimGrid.rst
examples/python/CMakeLists.txt
examples/python/exec-ptask/exec-ptask.py [new file with mode: 0644]
examples/python/exec-ptask/exec-ptask.tesh [new file with mode: 0644]
examples/sthread/CMakeLists.txt [new file with mode: 0644]
examples/sthread/pthread-mutex-simple.c [new file with mode: 0644]
examples/sthread/pthread-mutex-simple.tesh [new file with mode: 0644]
examples/sthread/sthread-mutex-simple.c [new file with mode: 0644]
include/simgrid/Exception.hpp
include/simgrid/forward.h
include/xbt/asserts.hpp [new file with mode: 0644]
src/bindings/python/simgrid_python.cpp
src/kernel/EngineImpl.cpp
src/kernel/context/Context.cpp
src/kernel/context/ContextSwapped.cpp
src/kernel/routing/NetZoneImpl.cpp
src/kernel/routing/RoutedZone.cpp
src/mc/api/State.cpp
src/mc/mc_pattern.hpp
src/mc/remote/AppSide.cpp
src/simgrid/Exception.cpp
src/smpi/include/private.hpp
src/smpi/internals/smpi_global.cpp
src/sthread/sthread.c [new file with mode: 0644]
src/sthread/sthread.h [new file with mode: 0644]
src/sthread/sthread_impl.cpp [new file with mode: 0644]
src/surf/HostImpl.cpp
src/xbt/xbt_main.cpp
teshsuite/s4u/issue71/issue71.cpp
teshsuite/s4u/issue71/issue71.tesh
tools/cmake/DefinePackages.cmake
tools/cmake/Distrib.cmake
tools/cmake/MakeLib.cmake

index 8c942b8..3738be9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 SimGrid (3.31.1) NOT RELEASED YET (v3.32 expected June 21. 2022, 09:13 UTC)
 
+S4U:
+  - Added the xbt_enforce macro. This has the same syntax as xbt_assert. The only difference is that an AssertionError
+    exception is thrown if the condition is not satisfied, instead of calling abort().
+
 Python:
   - Added the following bindings / examples:
     - Comm (now 100% covers the C++ interface):
@@ -15,7 +19,15 @@ Python:
     - Engine:
       - Engine.host_by_name [example: examples/python/comm-host2host/]
       - Engine.mailbox_by_name_or_create [example: examples/python/comm-pingpong/]
+         - Engine.set_config
     - Mailbox: Mailbox.ready [example: examples/python/comm-ready/]
+       - Ptask [example: examples/python/exec-ptask/]:
+         - this_actor.exec_init
+         - this_actor.parallel_execute
+         - Exec.suspend
+         - Exec.wait_for
+  - Added an AssertionError exception that may be thrown in case of error. For instance, creating tow hosts with the
+    same name will now throw this exception instead of killing the interpreter.
 
 Platform description & visualization:
   - More robust sanity checks for platforms, to reject unallowed topologies with
@@ -40,6 +52,7 @@ Fixed bugs (FG#.. -> FramaGit bugs; FG!.. -> FG merge requests)
  (FG: issues on Framagit; GH: issues on GitHub)
  - FG#105: "Variable penalty should not be negative!" with in-flight messages and bandwidth profiles
  - FG#109: Application time reported by --cfg=smpi/display-timing:yes is wrong
+ - FG!109: Trigger new engine solve upon host events such as host on/off
  - FG#110: Wait_any does not trigger new model solve when host events occur
 
 ----------------------------------------------------------------------------
index c3f49ce..09a068e 100644 (file)
@@ -553,6 +553,8 @@ include examples/python/exec-async/exec-async.py
 include examples/python/exec-async/exec-async.tesh
 include examples/python/exec-basic/exec-basic.py
 include examples/python/exec-basic/exec-basic.tesh
+include examples/python/exec-basic/exec-ptask.py
+include examples/python/exec-basic/exec-ptask.tesh
 include examples/python/exec-cpu-nonlinear/exec-cpu-nonlinear.py
 include examples/python/exec-cpu-nonlinear/exec-cpu-nonlinear.tesh
 include examples/python/exec-dvfs/exec-dvfs.py
@@ -710,6 +712,8 @@ include examples/smpi/trace_call_location/trace_call_location.c
 include examples/smpi/trace_call_location/trace_call_location.tesh
 include examples/smpi/trace_simple/trace_simple.c
 include examples/smpi/trace_simple/trace_simple.tesh
+include examples/sthread/pthread-mutex-simple.c
+include examples/sthread/sthread-mutex-simple.c
 include src/include/catch_simgrid.hpp
 include teshsuite/java/semaphoregc/SemaphoreGC.java
 include teshsuite/java/semaphoregc/semaphoregc.tesh
@@ -1973,6 +1977,7 @@ include examples/smpi/comm_dynamic_costs/CMakeLists.txt
 include examples/smpi/replay_multiple/CMakeLists.txt
 include examples/smpi/replay_multiple_manual_deploy/CMakeLists.txt
 include examples/smpi/smpi_s4u_masterworker/CMakeLists.txt
+include examples/sthread/CMakeLists.txt
 include include/simgrid/Exception.hpp
 include include/simgrid/actor.h
 include include/simgrid/barrier.h
@@ -2054,6 +2059,7 @@ include include/xbt.h
 include include/xbt/Extendable.hpp
 include include/xbt/PropertyHolder.hpp
 include include/xbt/asserts.h
+include include/xbt/asserts.hpp
 include include/xbt/automaton.h
 include include/xbt/automaton.hpp
 include include/xbt/backtrace.hpp
@@ -2584,6 +2590,9 @@ include src/smpi/smpif90.in
 include src/smpi/smpiff.in
 include src/smpi/smpirun.in
 include src/smpi/smpitools.sh
+include src/sthread/sthread.c
+include src/sthread/sthread.h
+include src/sthread/sthread_impl.cpp
 include src/surf/HostImpl.cpp
 include src/surf/HostImpl.hpp
 include src/surf/cpu_cas01.cpp
index 2626419..9d5d606 100644 (file)
@@ -146,7 +146,7 @@ Grab the last **stable release** from `FramaGit
 
    $ tar xf simgrid-3-XX.tar.gz
    $ cd simgrid-*
-   $ cmake -DCMAKE_INSTALL_PREFIX=/opt/simgrid .
+   $ cmake -DCMAKE_INSTALL_PREFIX=/opt/simgrid -GNinja.
    $ make
    $ make install
 
index 48f69d4..1efe8e2 100644 (file)
@@ -2,7 +2,7 @@ foreach(example actor-create actor-daemon actor-join actor-kill actor-migrate ac
         app-masterworkers
         comm-wait comm-waitall comm-waitallfor comm-waitany comm-waitfor comm-failure comm-host2host comm-pingpong
         comm-ready comm-serialize comm-suspend comm-testany comm-throttling comm-waitallfor comm-waituntil
-        exec-async exec-basic exec-dvfs exec-remote
+        exec-async exec-basic exec-dvfs exec-remote exec-ptask
         platform-profile platform-failures
         network-nonlinear clusters-multicpu io-degradation exec-cpu-nonlinear
         synchro-barrier synchro-mutex synchro-semaphore)
diff --git a/examples/python/exec-ptask/exec-ptask.py b/examples/python/exec-ptask/exec-ptask.py
new file mode 100644 (file)
index 0000000..d5ddb6a
--- /dev/null
@@ -0,0 +1,103 @@
+# Copyright (c) 2018-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.
+
+
+# This script does exactly the same thing as file s4u-exec-ptask.cpp
+
+import sys
+from simgrid import Actor, Engine, Host, this_actor, TimeoutException
+
+def runner():
+    hosts = Engine.instance.all_hosts
+    hosts_count = len(hosts)
+
+    # Test 1
+    this_actor.info("First, build a classical parallel activity, with 1 Gflop to execute on each node, "
+               "and 10MB to exchange between each pair")
+    computation_amounts = [1e9]*hosts_count
+    communication_amounts = [0]*hosts_count*hosts_count
+    for i in range(hosts_count):
+        for j in range(i+1, hosts_count):
+            communication_amounts[i * hosts_count + j] = 1e7
+    this_actor.parallel_execute(hosts, computation_amounts, communication_amounts)
+
+    # Test 2
+    this_actor.info("We can do the same with a timeout of 10 seconds enabled.")
+    activity = this_actor.exec_init(hosts, computation_amounts, communication_amounts)
+    try:
+        activity.wait_for(10.0)
+        sys.exit("Woops, this did not timeout as expected... Please report that bug.")
+    except TimeoutException:
+        this_actor.info("Caught the expected timeout exception.")
+        activity.cancel()
+
+    # Test 3
+    this_actor.info("Then, build a parallel activity involving only computations (of different amounts) and no communication")
+    computation_amounts = [3e8, 6e8, 1e9]
+    communication_amounts = []
+    this_actor.parallel_execute(hosts, computation_amounts, communication_amounts)
+
+    # Test 4
+    this_actor.info("Then, build a parallel activity with no computation nor communication (synchro only)")
+    computation_amounts = []
+    this_actor.parallel_execute(hosts, computation_amounts, communication_amounts)
+
+    # Test 5
+    this_actor.info("Then, Monitor the execution of a parallel activity")
+    computation_amounts = [1e6]*hosts_count
+    communication_amounts = [0, 1e6, 0, 0, 0, 1e6, 1e6, 0, 0]
+    activity = this_actor.exec_init(hosts, computation_amounts, communication_amounts)
+    activity.start()
+    while not activity.test():
+        ratio = activity.remaining_ratio * 100
+        this_actor.info(f"Remaining flop ratio: {ratio:.0f}%")
+        this_actor.sleep_for(5)
+    activity.wait()
+
+    # Test 6
+    this_actor.info("Finally, simulate a malleable task (a parallel execution that gets reconfigured after its start).")
+    this_actor.info("  - Start a regular parallel execution, with both comm and computation")
+    computation_amounts = [1e6]*hosts_count
+    communication_amounts = [0, 1e6, 0, 0, 1e6, 0, 1e6, 0, 0]
+    activity = this_actor.exec_init(hosts, computation_amounts, communication_amounts)
+    activity.start()
+    this_actor.sleep_for(10)
+    remaining_ratio = activity.remaining_ratio
+    this_actor.info(f"  - After 10 seconds, {remaining_ratio*100:.2f}% remains to be done. Change it from 3 hosts to 2 hosts only.")
+    this_actor.info("    Let's first suspend the task.")
+    activity.suspend()
+    this_actor.info("  - Now, simulate the reconfiguration (modeled as a comm from the removed host to the remaining ones).")
+    rescheduling_comp = [0, 0, 0]
+    rescheduling_comm = [0, 0, 0, 0, 0, 0, 25000, 25000, 0]
+    this_actor.parallel_execute(hosts, rescheduling_comp, rescheduling_comm)
+    this_actor.info("  - Now, let's cancel the old task and create a new task with modified comm and computation vectors:")
+    this_actor.info("    What was already done is removed, and the load of the removed host is shared between remaining ones.")
+    for i in range(2):
+        # remove what we've done so far, for both comm and compute load
+        computation_amounts[i]   *= remaining_ratio
+        communication_amounts[i] *= remaining_ratio
+        # The work from 1 must be shared between 2 remaining ones. 1/2=50% of extra work for each
+        computation_amounts[i]   *= 1.5;
+        communication_amounts[i] *= 1.5;
+    hosts = hosts[:2]
+    computation_amounts = computation_amounts[:2]
+    remaining_comm = communication_amounts[1]
+    communication_amounts = [0, remaining_comm, remaining_comm, 0]
+    activity.cancel()
+    activity = this_actor.exec_init(hosts, computation_amounts, communication_amounts)
+    this_actor.info("  - Done, let's wait for the task completion")
+    activity.wait()
+    this_actor.info("Goodbye now!")
+
+
+if __name__ == "__main__":
+    if len(sys.argv) != 2:
+        sys.exit(f"Syntax: {sys.argv[0]} <platform_file>")
+    platform = sys.argv[1]
+    engine = Engine.instance
+    Engine.set_config("host/model:ptask_L07")  # /!\ this is required for running ptasks
+    engine.load_platform(platform)
+    Actor.create("foo", engine.host_by_name("MyHost1"), runner)
+    engine.run()
diff --git a/examples/python/exec-ptask/exec-ptask.tesh b/examples/python/exec-ptask/exec-ptask.tesh
new file mode 100644 (file)
index 0000000..90ff802
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env tesh
+
+$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${srcdir}/exec-ptask.py ${platfdir}/energy_platform.xml
+> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'host/model' to 'ptask_L07'
+> [0.000000] [xbt_cfg/INFO] Switching to the L07 model to handle parallel tasks.
+> [MyHost1:foo:(1) 0.000000] [python/INFO] First, build a classical parallel activity, with 1 Gflop to execute on each node, and 10MB to exchange between each pair
+> [MyHost1:foo:(1) 300.000000] [python/INFO] We can do the same with a timeout of 10 seconds enabled.
+> [MyHost1:foo:(1) 310.000000] [python/INFO] Caught the expected timeout exception.
+> [MyHost1:foo:(1) 310.000000] [python/INFO] Then, build a parallel activity involving only computations (of different amounts) and no communication
+> [MyHost1:foo:(1) 320.000000] [python/INFO] Then, build a parallel activity with no computation nor communication (synchro only)
+> [MyHost1:foo:(1) 320.000000] [python/INFO] Then, Monitor the execution of a parallel activity
+> [MyHost1:foo:(1) 320.000000] [python/INFO] Remaining flop ratio: 100%
+> [MyHost1:foo:(1) 325.000000] [python/INFO] Remaining flop ratio: 83%
+> [MyHost1:foo:(1) 330.000000] [python/INFO] Remaining flop ratio: 67%
+> [MyHost1:foo:(1) 335.000000] [python/INFO] Remaining flop ratio: 50%
+> [MyHost1:foo:(1) 340.000000] [python/INFO] Remaining flop ratio: 33%
+> [MyHost1:foo:(1) 345.000000] [python/INFO] Remaining flop ratio: 17%
+> [MyHost1:foo:(1) 350.000000] [python/INFO] Finally, simulate a malleable task (a parallel execution that gets reconfigured after its start).
+> [MyHost1:foo:(1) 350.000000] [python/INFO]   - Start a regular parallel execution, with both comm and computation
+> [MyHost1:foo:(1) 360.000000] [python/INFO]   - After 10 seconds, 50.00% remains to be done. Change it from 3 hosts to 2 hosts only.
+> [MyHost1:foo:(1) 360.000000] [python/INFO]     Let's first suspend the task.
+> [MyHost1:foo:(1) 360.000000] [python/INFO]   - Now, simulate the reconfiguration (modeled as a comm from the removed host to the remaining ones).
+> [MyHost1:foo:(1) 360.500000] [python/INFO]   - Now, let's cancel the old task and create a new task with modified comm and computation vectors:
+> [MyHost1:foo:(1) 360.500000] [python/INFO]     What was already done is removed, and the load of the removed host is shared between remaining ones.
+> [MyHost1:foo:(1) 360.500000] [python/INFO]   - Done, let's wait for the task completion
+> [MyHost1:foo:(1) 375.500000] [python/INFO] Goodbye now!
diff --git a/examples/sthread/CMakeLists.txt b/examples/sthread/CMakeLists.txt
new file mode 100644 (file)
index 0000000..784b55a
--- /dev/null
@@ -0,0 +1,50 @@
+set(THREADS_PREFER_PTHREAD_FLAG ON)
+find_package(Threads REQUIRED)
+
+# Regular pthread examples: test the interceptor of the pthread interface
+#########################################################################
+
+foreach(x
+        mutex-simple)
+
+  if("${CMAKE_SYSTEM}" MATCHES "Linux")
+    add_executable       (pthread-${x} EXCLUDE_FROM_ALL pthread-${x}.c)
+    set_target_properties(pthread-${x} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+    target_link_libraries(pthread-${x} PRIVATE Threads::Threads)
+
+    add_dependencies(tests pthread-${x})
+    ADD_TESH_FACTORIES(pthread-${x} "^thread" --setenv LD_PRELOAD=${CMAKE_BINARY_DIR}/lib/libsthread.so --cd ${CMAKE_BINARY_DIR}/examples/sthread ${CMAKE_CURRENT_SOURCE_DIR}/pthread-${x}.tesh)
+  endif()
+
+  set(tesh_files    ${tesh_files}    ${CMAKE_CURRENT_SOURCE_DIR}/pthread-${x}.tesh)
+  set(examples_src  ${examples_src}  ${CMAKE_CURRENT_SOURCE_DIR}/pthread-${x}.c)
+
+endforeach()
+
+# Regular sthread examples: test the internal interface for debugging purpose
+#############################################################################
+
+foreach(x
+        mutex-simple)
+  if("${CMAKE_SYSTEM}" MATCHES "Linux")
+    add_executable       (sthread-${x} EXCLUDE_FROM_ALL sthread-${x}.c)
+    set_target_properties(sthread-${x} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+    target_link_libraries(sthread-${x} sthread)
+    set_property(TARGET sthread-${x} APPEND PROPERTY INCLUDE_DIRECTORIES "${INTERNAL_INCLUDES}")
+    add_dependencies(tests sthread-${x})
+  endif()
+
+#  set(tesh_files    ${tesh_files}    ${CMAKE_CURRENT_SOURCE_DIR}/sthread-${x}.tesh)
+  set(examples_src  ${examples_src}  ${CMAKE_CURRENT_SOURCE_DIR}/sthread-${x}.c)
+endforeach()
+
+
+# Add all extra files to the archive
+####################################
+
+set(tesh_files    ${tesh_files}     PARENT_SCOPE)
+set(bin_files     ${bin_files}      PARENT_SCOPE)
+set(examples_src  ${examples_src}   PARENT_SCOPE)
+set(xml_files     ${xml_files}      PARENT_SCOPE)
+
+
diff --git a/examples/sthread/pthread-mutex-simple.c b/examples/sthread/pthread-mutex-simple.c
new file mode 100644 (file)
index 0000000..d46d75a
--- /dev/null
@@ -0,0 +1,32 @@
+/* Simple test code with no bug  */
+
+#include <pthread.h>
+#include <stdio.h>
+
+pthread_mutex_t mutex;
+
+static void* thread_fun(void* val)
+{
+  pthread_mutex_lock(&mutex);
+  pthread_mutex_unlock(&mutex);
+
+  fprintf(stderr, "The thread %d is terminating.\n", *(int*)val);
+  return NULL;
+}
+
+int main(int argc, char* argv[])
+{
+  pthread_mutex_init(&mutex, NULL);
+
+  int id[2] = {0, 1};
+  pthread_t thread1;
+  pthread_t thread2;
+  pthread_create(&thread1, NULL, thread_fun, (void*)&id[0]);
+  pthread_create(&thread2, NULL, thread_fun, (void*)&id[1]);
+  fprintf(stderr, "All threads are started.\n");
+  pthread_join(thread1, NULL);
+  pthread_join(thread2, NULL);
+
+  fprintf(stderr, "User's main is terminating.\n");
+  return 0;
+}
diff --git a/examples/sthread/pthread-mutex-simple.tesh b/examples/sthread/pthread-mutex-simple.tesh
new file mode 100644 (file)
index 0000000..b3bba4d
--- /dev/null
@@ -0,0 +1,7 @@
+$ ./pthread-mutex-simple
+> [0.000000] [sthread/INFO] Starting the simulation.
+> The thread 0 is terminating.
+> All threads are started.
+> The thread 1 is terminating.
+> User's main is terminating.
+> [0.000000] [sthread/INFO] All threads exited. Terminating the simulation.
\ No newline at end of file
diff --git a/examples/sthread/sthread-mutex-simple.c b/examples/sthread/sthread-mutex-simple.c
new file mode 100644 (file)
index 0000000..3ab8267
--- /dev/null
@@ -0,0 +1,29 @@
+/* Simple test code with no bug  */
+
+#include "src/sthread/sthread.h"
+#include <stdio.h>
+
+sthread_mutex_t mutex;
+
+static void* thread_fun(void* ignore)
+{
+  sthread_mutex_lock(&mutex);
+  sthread_mutex_unlock(&mutex);
+
+  return NULL;
+}
+
+int main(int argc, char* argv[])
+{
+  sthread_mutex_init(&mutex, NULL);
+
+  sthread_t thread1;
+  sthread_t thread2;
+  sthread_create(&thread1, NULL, thread_fun, NULL);
+  sthread_create(&thread2, NULL, thread_fun, NULL);
+  sthread_join(thread1, NULL);
+  sthread_join(thread2, NULL);
+  fprintf(stderr, "done\n");
+
+  return 0;
+}
index 304295a..342bd4b 100644 (file)
@@ -153,6 +153,9 @@ DECLARE_SIMGRID_EXCEPTION(TracingError);
 DECLARE_SIMGRID_EXCEPTION(ParseError, PARSE_ERROR_CONSTRUCTOR);
 #undef PARSE_ERROR_CONSTRUCTOR
 
+/** Exception raised by xbt_enforce, when an assertion is not satisfied */
+DECLARE_SIMGRID_EXCEPTION(AssertionError);
+
 #undef DECLARE_SIMGRID_EXCEPTION
 
 class XBT_PUBLIC ForcefulKillException {
index e8356af..9b81d2a 100644 (file)
@@ -324,4 +324,6 @@ typedef enum {
   SG_ERROR_VM
 } sg_error_t;
 
+XBT_PUBLIC int SMPI_is_inited();
+
 #endif /* SIMGRID_TYPES_H */
diff --git a/include/xbt/asserts.hpp b/include/xbt/asserts.hpp
new file mode 100644 (file)
index 0000000..84f647a
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (c) 2016-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_XBT_ASSERTS_HPP
+#define SIMGRID_XBT_ASSERTS_HPP
+
+#include <simgrid/Exception.hpp>
+
+/**
+ * @brief Those are the SimGrid version of the good ol' assert macro.
+ *
+ * You can pass them a format message and arguments, just as if it where a printf.
+ *
+ * If the statement evaluates to false, then a simgrid::AsertionError is thrown.
+ * This is identical to the xbt_assert macro, except that an exception is thrown instead of calling abort().
+ *
+ * Unlike the standard assert, xbt_enforce is never disabled, even if the macro NDEBUG is defined at compile time.
+ * Note however that this macro should *not* be used with a condition that has side effects, since the exception can be
+ * caught and ignored.
+ */
+/** @brief The condition which failed will be displayed.
+    @hideinitializer  */
+#define xbt_enforce(...) \
+  _XBT_IF_ONE_ARG(_xbt_enforce_ARG1, _xbt_enforce_ARGN, __VA_ARGS__)(__VA_ARGS__)
+#define _xbt_enforce_ARG1(cond) _xbt_enforce_ARGN((cond), "Assertion %s failed", #cond)
+#define _xbt_enforce_ARGN(cond, ...)                                                                                   \
+  do {                                                                                                                 \
+    if (!(cond)) {                                                                                                     \
+      throw simgrid::AssertionError(XBT_THROW_POINT, xbt::string_printf(__VA_ARGS__));                                 \
+    }                                                                                                                  \
+  } while (0)
+
+#endif
index 9d86a99..e1c42ed 100644 (file)
@@ -103,6 +103,7 @@ PYBIND11_MODULE(simgrid, m)
   py::register_exception<simgrid::StorageFailureException>(m, "StorageFailureException");
   py::register_exception<simgrid::VmFailureException>(m, "VmFailureException");
   py::register_exception<simgrid::CancelException>(m, "CancelException");
+  py::register_exception<simgrid::AssertionError>(m, "AssertionError");
 
   /* this_actor namespace */
   m.def_submodule("this_actor", "Bindings of the s4u::this_actor namespace. See the C++ documentation for details.")
@@ -122,6 +123,14 @@ PYBIND11_MODULE(simgrid, m)
            py::call_guard<py::gil_scoped_release>())
       .def("exec_async", py::overload_cast<double>(&simgrid::s4u::this_actor::exec_async),
            py::call_guard<py::gil_scoped_release>())
+      .def("parallel_execute", &simgrid::s4u::this_actor::parallel_execute,
+           py::call_guard<py::gil_scoped_release>(),
+           "Run a parallel task (requires the 'ptask_L07' model)")
+      .def("exec_init",
+           py::overload_cast<const std::vector<simgrid::s4u::Host*>&, const std::vector<double>&,
+           const std::vector<double>&>  (&simgrid::s4u::this_actor::exec_init),
+           py::call_guard<py::gil_scoped_release>(),
+           "Initiate a parallel task (requires the 'ptask_L07' model)")
       .def("get_host", &simgrid::s4u::this_actor::get_host, "Retrieves host on which the current actor is located")
       .def("set_host", &simgrid::s4u::this_actor::set_host, py::call_guard<py::gil_scoped_release>(),
            "Moves the current actor to another host.", py::arg("dest"))
@@ -218,6 +227,8 @@ PYBIND11_MODULE(simgrid, m)
                              "Retrieve the root netzone, containing all others.")
       .def("netpoint_by_name", &Engine::netpoint_by_name_or_null)
       .def("netzone_by_name", &Engine::netzone_by_name_or_null)
+      .def("set_config", py::overload_cast<const std::string&>(&Engine::set_config),
+           "Change one of SimGrid's configurations")
       .def("load_platform", &Engine::load_platform, "Load a platform file describing the environment")
       .def("load_deployment", &Engine::load_deployment, "Load a deployment file and launch the actors that it contains")
       .def("mailbox_by_name_or_create", &Engine::mailbox_by_name_or_create,
@@ -839,8 +850,12 @@ PYBIND11_MODULE(simgrid, m)
            "Test whether the execution is terminated.")
       .def("cancel", &simgrid::s4u::Exec::cancel, py::call_guard<py::gil_scoped_release>(), "Cancel that execution.")
       .def("start", &simgrid::s4u::Exec::start, py::call_guard<py::gil_scoped_release>(), "Start that execution.")
+      .def("suspend", &simgrid::s4u::Exec::suspend, py::call_guard<py::gil_scoped_release>(), "Suspend that execution.")
       .def("wait", &simgrid::s4u::Exec::wait, py::call_guard<py::gil_scoped_release>(),
-           "Block until the completion of that execution.");
+           "Block until the completion of that execution.")
+      .def("wait_for", &simgrid::s4u::Exec::wait_for, py::call_guard<py::gil_scoped_release>(),
+           py::arg("timeout"),
+           "Block until the completion of that activity, or raises TimeoutException after the specified timeout.");
 
   /* Class Semaphore */
   py::class_<Semaphore, SemaphorePtr>(m, "Semaphore",
index 7706219..00d0f16 100644 (file)
@@ -106,7 +106,7 @@ static void segvhandler(int signum, siginfo_t* siginfo, void* /*context*/)
   } else if (siginfo->si_signo == SIGSEGV) {
     fprintf(stderr, "Segmentation fault.\n");
 #if HAVE_SMPI
-    if (smpi_enabled() && smpi_cfg_privatization() == SmpiPrivStrategies::NONE) {
+    if (SMPI_is_inited() && smpi_cfg_privatization() == SmpiPrivStrategies::NONE) {
 #if HAVE_PRIVATIZATION
       fprintf(stderr, "Try to enable SMPI variable privatization with --cfg=smpi/privatization:yes.\n");
 #else
index 66a895b..6827ff9 100644 (file)
@@ -9,6 +9,7 @@
 #include "simgrid/s4u/Host.hpp"
 #include "src/kernel/activity/CommImpl.hpp"
 #include "src/kernel/context/Context.hpp"
+#include "src/sthread/sthread.h"
 #include "src/surf/surf_interface.hpp"
 
 #include <vector>
@@ -139,6 +140,7 @@ Context::~Context()
 void Context::stop()
 {
   this->actor_->cleanup_from_self();
+  sthread_disable();
   throw ForcefulKillException(); // clean RAII variables with the dedicated exception
 }
 AttachContext::~AttachContext() = default;
index c6812f4..599d52a 100644 (file)
@@ -8,6 +8,7 @@
 #include "src/internal_config.h"
 #include "src/kernel/EngineImpl.hpp"
 #include "src/kernel/actor/ActorImpl.hpp"
+#include "src/sthread/sthread.h"
 #include "xbt/parmap.hpp"
 
 #include "src/kernel/context/ContextSwapped.hpp"
@@ -48,11 +49,15 @@ void smx_ctx_wrapper(simgrid::kernel::context::SwappedContext* context)
   __sanitizer_finish_switch_fiber(nullptr, &context->asan_ctx_->asan_stack_, &context->asan_ctx_->asan_stack_size_);
 #endif
   try {
+    sthread_enable();
     (*context)();
+    sthread_disable();
     context->stop();
   } catch (simgrid::ForcefulKillException const&) {
+    sthread_disable();
     XBT_DEBUG("Caught a ForcefulKillException");
   } catch (simgrid::Exception const& e) {
+    sthread_disable();
     XBT_INFO("Actor killed by an uncaught exception %s", boost::core::demangle(typeid(e).name()).c_str());
     throw;
   }
@@ -244,6 +249,7 @@ void SwappedContext::resume()
     // Save my current soul (either maestro, or one of the minions) in a thread-specific area
     worker_context_ = old;
   }
+  sthread_enable();
   // Switch my soul and the actor's one
   Context::set_current(this);
   old->swap_into(this);
@@ -285,10 +291,12 @@ void SwappedContext::suspend()
     if (i < engine->get_actor_to_run_count()) {
       /* Actually swap into the next actor directly without transiting to maestro */
       XBT_DEBUG("Run next actor");
+      sthread_enable();
       next_context = static_cast<SwappedContext*>(engine->get_actor_to_run_at(i)->context_.get());
     } else {
       /* all processes were run, actually return to maestro */
       XBT_DEBUG("No more actors to run");
+      sthread_disable();
       next_context = factory_.maestro_context_;
     }
   }
index 78a8584..885e4e5 100644 (file)
@@ -9,6 +9,7 @@
 #include <simgrid/s4u/Host.hpp>
 #include <simgrid/s4u/VirtualMachine.hpp>
 
+#include "xbt/asserts.hpp"
 #include "src/include/simgrid/sg_config.hpp"
 #include "src/kernel/EngineImpl.hpp"
 #include "src/kernel/resource/CpuImpl.hpp"
@@ -40,8 +41,8 @@ static void surf_config_models_setup()
 
   XBT_DEBUG("host model: %s", host_model_name.c_str());
   if (host_model_name == "compound") {
-    xbt_assert(not cpu_model_name.empty(), "Set a cpu model to use with the 'compound' host model");
-    xbt_assert(not network_model_name.empty(), "Set a network model to use with the 'compound' host model");
+    xbt_enforce(not cpu_model_name.empty(), "Set a cpu model to use with the 'compound' host model");
+    xbt_enforce(not network_model_name.empty(), "Set a network model to use with the 'compound' host model");
 
     const auto* cpu_model = find_model_description(surf_cpu_model_description, cpu_model_name);
     cpu_model->model_init_preparse();
@@ -93,7 +94,7 @@ NetZoneImpl::NetZoneImpl(const std::string& name) : piface_(this), name_(name)
     surf_config_models_setup();
   }
 
-  xbt_assert(nullptr == engine->netpoint_by_name_or_null(get_name()),
+  xbt_enforce(nullptr == engine->netpoint_by_name_or_null(get_name()),
              "Refusing to create a second NetZone called '%s'.", get_cname());
   netpoint_ = new NetPoint(name_, NetPoint::Type::NetZone);
   XBT_DEBUG("NetZone '%s' created with the id '%lu'", get_cname(), netpoint_->id());
@@ -153,7 +154,7 @@ xbt_edge_t NetZoneImpl::new_xbt_graph_edge(const s_xbt_graph_t* graph, xbt_node_
 
 void NetZoneImpl::add_child(NetZoneImpl* new_zone)
 {
-  xbt_assert(not sealed_, "Cannot add a new child to the sealed zone %s", get_cname());
+  xbt_enforce(not sealed_, "Cannot add a new child to the sealed zone %s", get_cname());
   /* set the parent behavior */
   hierarchy_ = RoutingMode::recursive;
   children_.push_back(new_zone);
@@ -207,10 +208,10 @@ size_t NetZoneImpl::get_link_count() const
 
 s4u::Host* NetZoneImpl::create_host(const std::string& name, const std::vector<double>& speed_per_pstate)
 {
-  xbt_assert(cpu_model_pm_,
+  xbt_enforce(cpu_model_pm_,
              "Impossible to create host: %s. Invalid CPU model: nullptr. Have you set the parent of this NetZone: %s?",
              name.c_str(), get_cname());
-  xbt_assert(not sealed_, "Impossible to create host: %s. NetZone %s already sealed", name.c_str(), get_cname());
+  xbt_enforce(not sealed_, "Impossible to create host: %s. NetZone %s already sealed", name.c_str(), get_cname());
   auto* host   = (new resource::HostImpl(name))->set_englobing_zone(this);
   hosts_[name] = host;
   host->get_iface()->set_netpoint((new NetPoint(name, NetPoint::Type::Host))->set_englobing_zone(this));
@@ -227,11 +228,11 @@ resource::StandardLinkImpl* NetZoneImpl::do_create_link(const std::string& name,
 
 s4u::Link* NetZoneImpl::create_link(const std::string& name, const std::vector<double>& bandwidths)
 {
-  xbt_assert(
+  xbt_enforce(
       network_model_,
       "Impossible to create link: %s. Invalid network model: nullptr. Have you set the parent of this NetZone: %s?",
       name.c_str(), get_cname());
-  xbt_assert(not sealed_, "Impossible to create link: %s. NetZone %s already sealed", name.c_str(), get_cname());
+  xbt_enforce(not sealed_, "Impossible to create link: %s. NetZone %s already sealed", name.c_str(), get_cname());
   links_[name] = do_create_link(name, bandwidths)->set_englobing_zone(this);
   return links_[name]->get_iface();
 }
@@ -239,11 +240,11 @@ s4u::Link* NetZoneImpl::create_link(const std::string& name, const std::vector<d
 s4u::SplitDuplexLink* NetZoneImpl::create_split_duplex_link(const std::string& name,
                                                             const std::vector<double>& bandwidths)
 {
-  xbt_assert(
+  xbt_enforce(
       network_model_,
       "Impossible to create link: %s. Invalid network model: nullptr. Have you set the parent of this NetZone: %s?",
       name.c_str(), get_cname());
-  xbt_assert(not sealed_, "Impossible to create link: %s. NetZone %s already sealed", name.c_str(), get_cname());
+  xbt_enforce(not sealed_, "Impossible to create link: %s. NetZone %s already sealed", name.c_str(), get_cname());
 
   auto* link_up             = create_link(name + "_UP", bandwidths)->get_impl()->set_englobing_zone(this);
   auto* link_down           = create_link(name + "_DOWN", bandwidths)->get_impl()->set_englobing_zone(this);
@@ -253,10 +254,10 @@ s4u::SplitDuplexLink* NetZoneImpl::create_split_duplex_link(const std::string& n
 
 s4u::Disk* NetZoneImpl::create_disk(const std::string& name, double read_bandwidth, double write_bandwidth)
 {
-  xbt_assert(disk_model_,
+  xbt_enforce(disk_model_,
              "Impossible to create disk: %s. Invalid disk model: nullptr. Have you set the parent of this NetZone: %s?",
              name.c_str(), get_cname());
-  xbt_assert(not sealed_, "Impossible to create disk: %s. NetZone %s already sealed", name.c_str(), get_cname());
+  xbt_enforce(not sealed_, "Impossible to create disk: %s. NetZone %s already sealed", name.c_str(), get_cname());
   auto* l = disk_model_->create_disk(name, read_bandwidth, write_bandwidth);
 
   return l->get_iface();
@@ -264,9 +265,9 @@ s4u::Disk* NetZoneImpl::create_disk(const std::string& name, double read_bandwid
 
 NetPoint* NetZoneImpl::create_router(const std::string& name)
 {
-  xbt_assert(nullptr == s4u::Engine::get_instance()->netpoint_by_name_or_null(name),
+  xbt_enforce(nullptr == s4u::Engine::get_instance()->netpoint_by_name_or_null(name),
              "Refusing to create a router named '%s': this name already describes a node.", name.c_str());
-  xbt_assert(not sealed_, "Impossible to create router: %s. NetZone %s already sealed", name.c_str(), get_cname());
+  xbt_enforce(not sealed_, "Impossible to create router: %s. NetZone %s already sealed", name.c_str(), get_cname());
 
   return (new NetPoint(name, NetPoint::Type::Router))->set_englobing_zone(this);
 }
@@ -289,7 +290,7 @@ std::vector<resource::StandardLinkImpl*> NetZoneImpl::get_link_list_impl(const s
     }
     // split-duplex links
     const auto* sd_link = dynamic_cast<const s4u::SplitDuplexLink*>(link.get_link());
-    xbt_assert(sd_link,
+    xbt_enforce(sd_link,
                "Add_route: cast to SpliDuplexLink impossible. This should not happen, please contact SimGrid team");
     resource::StandardLinkImpl* link_impl;
     switch (link.get_direction()) {
@@ -390,16 +391,16 @@ void NetZoneImpl::add_bypass_route(NetPoint* src, NetPoint* dst, NetPoint* gw_sr
   if (gw_dst) {
     XBT_DEBUG("Load bypassNetzoneRoute from %s@%s to %s@%s", src->get_cname(), gw_src->get_cname(), dst->get_cname(),
               gw_dst->get_cname());
-    xbt_assert(not link_list.empty(), "Bypass route between %s@%s and %s@%s cannot be empty.", src->get_cname(),
+    xbt_enforce(not link_list.empty(), "Bypass route between %s@%s and %s@%s cannot be empty.", src->get_cname(),
                gw_src->get_cname(), dst->get_cname(), gw_dst->get_cname());
-    xbt_assert(bypass_routes_.find({src, dst}) == bypass_routes_.end(),
+    xbt_enforce(bypass_routes_.find({src, dst}) == bypass_routes_.end(),
                "The bypass route between %s@%s and %s@%s already exists.", src->get_cname(), gw_src->get_cname(),
                dst->get_cname(), gw_dst->get_cname());
   } else {
     XBT_DEBUG("Load bypassRoute from %s to %s", src->get_cname(), dst->get_cname());
-    xbt_assert(not link_list.empty(), "Bypass route between %s and %s cannot be empty.", src->get_cname(),
+    xbt_enforce(not link_list.empty(), "Bypass route between %s and %s cannot be empty.", src->get_cname(),
                dst->get_cname());
-    xbt_assert(bypass_routes_.find({src, dst}) == bypass_routes_.end(),
+    xbt_enforce(bypass_routes_.find({src, dst}) == bypass_routes_.end(),
                "The bypass route between %s and %s already exists.", src->get_cname(), dst->get_cname());
   }
 
@@ -480,8 +481,8 @@ static void find_common_ancestors(const NetPoint* src, const NetPoint* dst,
   const NetZoneImpl* src_as = src->get_englobing_zone();
   const NetZoneImpl* dst_as = dst->get_englobing_zone();
 
-  xbt_assert(src_as, "Host %s must be in a netzone", src->get_cname());
-  xbt_assert(dst_as, "Host %s must be in a netzone", dst->get_cname());
+  xbt_enforce(src_as, "Host %s must be in a netzone", src->get_cname());
+  xbt_enforce(dst_as, "Host %s must be in a netzone", dst->get_cname());
 
   /* (2) find the path to the root routing component */
   std::vector<NetZoneImpl*> path_src;
@@ -516,7 +517,7 @@ static void find_common_ancestors(const NetPoint* src, const NetPoint* dst,
   if (*src_ancestor == *dst_ancestor) {             // src is the ancestor of dst, or the contrary
     *common_ancestor = *src_ancestor;
   } else {
-    xbt_assert(parent != nullptr);
+    xbt_enforce(parent != nullptr);
     *common_ancestor = parent;
   }
 }
@@ -646,7 +647,7 @@ void NetZoneImpl::get_global_route_with_netzones(const NetPoint* src, const NetP
 
   /* Not in the same netzone, no bypass. We'll have to find our path between the netzones recursively */
   common_ancestor->get_local_route(src_ancestor->netpoint_, dst_ancestor->netpoint_, &route, latency);
-  xbt_assert((route.gw_src_ != nullptr) && (route.gw_dst_ != nullptr), "Bad gateways for route from '%s' to '%s'.",
+  xbt_enforce((route.gw_src_ != nullptr) && (route.gw_dst_ != nullptr), "Bad gateways for route from '%s' to '%s'.",
              src->get_cname(), dst->get_cname());
 
   /* If source gateway is not our source, we have to recursively find our way up to this point */
@@ -736,7 +737,7 @@ void NetZoneImpl::seal()
 
 void NetZoneImpl::set_parent(NetZoneImpl* parent)
 {
-  xbt_assert(not sealed_, "Impossible to set parent to an already sealed NetZone(%s)", this->get_cname());
+  xbt_enforce(not sealed_, "Impossible to set parent to an already sealed NetZone(%s)", this->get_cname());
   parent_ = parent;
   netpoint_->set_englobing_zone(parent_);
   if (parent) {
@@ -753,37 +754,37 @@ void NetZoneImpl::set_parent(NetZoneImpl* parent)
 
 void NetZoneImpl::set_network_model(std::shared_ptr<resource::NetworkModel> netmodel)
 {
-  xbt_assert(not sealed_, "Impossible to set network model to an already sealed NetZone(%s)", this->get_cname());
+  xbt_enforce(not sealed_, "Impossible to set network model to an already sealed NetZone(%s)", this->get_cname());
   network_model_ = std::move(netmodel);
 }
 
 void NetZoneImpl::set_cpu_vm_model(std::shared_ptr<resource::CpuModel> cpu_model)
 {
-  xbt_assert(not sealed_, "Impossible to set CPU model to an already sealed NetZone(%s)", this->get_cname());
+  xbt_enforce(not sealed_, "Impossible to set CPU model to an already sealed NetZone(%s)", this->get_cname());
   cpu_model_vm_ = std::move(cpu_model);
 }
 
 void NetZoneImpl::set_cpu_pm_model(std::shared_ptr<resource::CpuModel> cpu_model)
 {
-  xbt_assert(not sealed_, "Impossible to set CPU model to an already sealed NetZone(%s)", this->get_cname());
+  xbt_enforce(not sealed_, "Impossible to set CPU model to an already sealed NetZone(%s)", this->get_cname());
   cpu_model_pm_ = std::move(cpu_model);
 }
 
 void NetZoneImpl::set_disk_model(std::shared_ptr<resource::DiskModel> disk_model)
 {
-  xbt_assert(not sealed_, "Impossible to set disk model to an already sealed NetZone(%s)", this->get_cname());
+  xbt_enforce(not sealed_, "Impossible to set disk model to an already sealed NetZone(%s)", this->get_cname());
   disk_model_ = std::move(disk_model);
 }
 
 void NetZoneImpl::set_host_model(std::shared_ptr<resource::HostModel> host_model)
 {
-  xbt_assert(not sealed_, "Impossible to set host model to an already sealed NetZone(%s)", this->get_cname());
+  xbt_enforce(not sealed_, "Impossible to set host model to an already sealed NetZone(%s)", this->get_cname());
   host_model_ = std::move(host_model);
 }
 
 const NetZoneImpl* NetZoneImpl::get_netzone_recursive(const NetPoint* netpoint) const
 {
-  xbt_assert(netpoint && netpoint->is_netzone(), "Netpoint %s must be of the type NetZone",
+  xbt_enforce(netpoint && netpoint->is_netzone(), "Netpoint %s must be of the type NetZone",
              netpoint ? netpoint->get_cname() : "nullptr");
 
   if (netpoint == netpoint_)
index 4534368..e7c2c79 100644 (file)
@@ -10,6 +10,7 @@
 #include "xbt/graph.h"
 #include "xbt/log.h"
 #include "xbt/sysdep.h"
+#include "xbt/asserts.hpp"
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ker_routing_generic, ker_routing, "Kernel Generic Routing");
 
@@ -26,11 +27,10 @@ RoutedZone::RoutedZone(const std::string& name) : NetZoneImpl(name) {}
 Route* RoutedZone::new_extended_route(RoutingMode hierarchy, NetPoint* gw_src, NetPoint* gw_dst,
                                       const std::vector<resource::StandardLinkImpl*>& link_list, bool preserve_order)
 {
-  auto* result = new Route();
+  xbt_enforce(hierarchy != RoutingMode::recursive || (gw_src && gw_dst), "nullptr is obviously a deficient gateway");
 
+  auto* result = new Route();
   if (hierarchy == RoutingMode::recursive) {
-    xbt_assert(gw_src && gw_dst, "nullptr is obviously a deficient gateway");
-
     result->gw_src_ = gw_src;
     result->gw_dst_ = gw_dst;
   }
@@ -46,17 +46,17 @@ Route* RoutedZone::new_extended_route(RoutingMode hierarchy, NetPoint* gw_src, N
 
 void RoutedZone::get_route_check_params(const NetPoint* src, const NetPoint* dst) const
 {
-  xbt_assert(src, "Cannot have a route with (nullptr) source");
-  xbt_assert(dst, "Cannot have a route with (nullptr) destination");
+  xbt_enforce(src, "Cannot have a route with (nullptr) source");
+  xbt_enforce(dst, "Cannot have a route with (nullptr) destination");
 
   const NetZoneImpl* src_as = src->get_englobing_zone();
   const NetZoneImpl* dst_as = dst->get_englobing_zone();
 
-  xbt_assert(src_as == dst_as,
+  xbt_enforce(src_as == dst_as,
              "Internal error: %s@%s and %s@%s are not in the same netzone as expected. Please report that bug.",
              src->get_cname(), src_as->get_cname(), dst->get_cname(), dst_as->get_cname());
 
-  xbt_assert(this == dst_as,
+  xbt_enforce(this == dst_as,
              "Internal error: route destination %s@%s is not in netzone %s as expected (route source: "
              "%s@%s). Please report that bug.",
              src->get_cname(), dst->get_cname(), src_as->get_cname(), dst_as->get_cname(), get_cname());
@@ -71,40 +71,40 @@ void RoutedZone::add_route_check_params(NetPoint* src, NetPoint* dst, NetPoint*
 
   if (not gw_dst || not gw_src) {
     XBT_DEBUG("Load Route from \"%s\" to \"%s\"", srcName, dstName);
-    xbt_assert(not link_list.empty(), "Empty route (between %s and %s) forbidden.", srcName, dstName);
-    xbt_assert(not src->is_netzone(),
+    xbt_enforce(not link_list.empty(), "Empty route (between %s and %s) forbidden.", srcName, dstName);
+    xbt_enforce(not src->is_netzone(),
                "When defining a route, src cannot be a netzone such as '%s'. Did you meant to have a NetzoneRoute?",
                srcName);
-    xbt_assert(not dst->is_netzone(),
+    xbt_enforce(not dst->is_netzone(),
                "When defining a route, dst cannot be a netzone such as '%s'. Did you meant to have a NetzoneRoute?",
                dstName);
     NetZoneImpl::on_route_creation(symmetrical, src, dst, gw_src, gw_dst, get_link_list_impl(link_list, false));
   } else {
     XBT_DEBUG("Load NetzoneRoute from %s@%s to %s@%s", srcName, gw_src->get_cname(), dstName, gw_dst->get_cname());
-    xbt_assert(src->is_netzone(), "When defining a NetzoneRoute, src must be a netzone but '%s' is not", srcName);
-    xbt_assert(dst->is_netzone(), "When defining a NetzoneRoute, dst must be a netzone but '%s' is not", dstName);
+    xbt_enforce(src->is_netzone(), "When defining a NetzoneRoute, src must be a netzone but '%s' is not", srcName);
+    xbt_enforce(dst->is_netzone(), "When defining a NetzoneRoute, dst must be a netzone but '%s' is not", dstName);
 
-    xbt_assert(gw_src->is_host() || gw_src->is_router(),
+    xbt_enforce(gw_src->is_host() || gw_src->is_router(),
                "When defining a NetzoneRoute, gw_src must be a host or a router but '%s' is not.", srcName);
-    xbt_assert(gw_dst->is_host() || gw_dst->is_router(),
+    xbt_enforce(gw_dst->is_host() || gw_dst->is_router(),
                "When defining a NetzoneRoute, gw_dst must be a host or a router but '%s' is not.", dstName);
 
-    xbt_assert(gw_src != gw_dst, "Cannot define a NetzoneRoute from '%s' to itself", gw_src->get_cname());
+    xbt_enforce(gw_src != gw_dst, "Cannot define a NetzoneRoute from '%s' to itself", gw_src->get_cname());
 
-    xbt_assert(src, "Cannot add a route from %s@%s to %s@%s: %s does not exist.", srcName, gw_src->get_cname(), dstName,
+    xbt_enforce(src, "Cannot add a route from %s@%s to %s@%s: %s does not exist.", srcName, gw_src->get_cname(), dstName,
                gw_dst->get_cname(), srcName);
-    xbt_assert(dst, "Cannot add a route from %s@%s to %s@%s: %s does not exist.", srcName, gw_src->get_cname(), dstName,
+    xbt_enforce(dst, "Cannot add a route from %s@%s to %s@%s: %s does not exist.", srcName, gw_src->get_cname(), dstName,
                gw_dst->get_cname(), dstName);
-    xbt_assert(not link_list.empty(), "Empty route (between %s@%s and %s@%s) forbidden.", srcName, gw_src->get_cname(),
+    xbt_enforce(not link_list.empty(), "Empty route (between %s@%s and %s@%s) forbidden.", srcName, gw_src->get_cname(),
                dstName, gw_dst->get_cname());
     const auto* netzone_src = get_netzone_recursive(src);
-    xbt_assert(netzone_src->is_component_recursive(gw_src),
+    xbt_enforce(netzone_src->is_component_recursive(gw_src),
                "Invalid NetzoneRoute from %s@%s to %s@%s: gw_src %s belongs to %s, not to %s.", srcName,
                gw_src->get_cname(), dstName, gw_dst->get_cname(), gw_src->get_cname(),
                gw_src->get_englobing_zone()->get_cname(), srcName);
 
     const auto* netzone_dst = get_netzone_recursive(dst);
-    xbt_assert(netzone_dst->is_component_recursive(gw_dst),
+    xbt_enforce(netzone_dst->is_component_recursive(gw_dst),
                "Invalid NetzoneRoute from %s@%s to %s@%s: gw_dst %s belongs to %s, not to %s.", srcName,
                gw_src->get_cname(), dstName, gw_dst->get_cname(), gw_dst->get_cname(),
                gw_dst->get_englobing_zone()->get_cname(), dst->get_cname());
index e3048b1..fac456f 100644 (file)
@@ -54,18 +54,13 @@ int State::next_transition() const
 void State::execute_next(int next)
 {
   std::vector<ActorInformation>& actors = mc_model_checker->get_remote_process().actors();
-
   const kernel::actor::ActorImpl* actor = actors[next].copy.get_buffer();
-  aid_t aid                       = actor->get_pid();
-  int times_considered;
+  const aid_t aid                       = actor->get_pid();
 
-  simgrid::mc::ActorState* actor_state = &actor_states_[aid];
   /* This actor is ready to be executed. Prepare its execution when simcall_handle will be called on it */
-  times_considered = actor_state->get_times_considered_and_inc();
-  if (actor->simcall_.mc_max_consider_ <= actor_state->get_times_considered())
-    actor_state->set_done();
+  const unsigned times_considered = actor_states_[aid].do_consider(actor->simcall_.mc_max_consider_);
 
-  XBT_DEBUG("Let's run actor %ld (times_considered = %d)", aid, times_considered);
+  XBT_DEBUG("Let's run actor %ld (times_considered = %u)", aid, times_considered);
 
   Transition::executed_transitions_++;
 
index 8702a24..e29895c 100644 (file)
@@ -35,8 +35,13 @@ class ActorState {
   unsigned int times_considered_ = 0;
 
 public:
+  unsigned int do_consider(unsigned int max_consider)
+  {
+    if (max_consider <= times_considered_ + 1)
+      set_done();
+    return times_considered_++;
+  }
   unsigned int get_times_considered() const { return times_considered_; }
-  unsigned int get_times_considered_and_inc() { return times_considered_++; }
 
   bool is_disabled() const { return this->state_ == InterleavingType::disabled; }
   bool is_done() const { return this->state_ == InterleavingType::done; }
index 8d612f1..2d4dfbe 100644 (file)
@@ -137,8 +137,8 @@ void AppSide::handle_finalize(const s_mc_message_int_t* msg) const
     if (XBT_LOG_ISENABLED(mc_client, xbt_log_priority_debug))
       kernel::EngineImpl::get_instance()->display_all_actor_status();
 #if HAVE_SMPI
-    XBT_DEBUG("Smpi_enabled: %d", (int)smpi_enabled());
-    if (smpi_enabled())
+    XBT_DEBUG("Smpi_enabled: %d", SMPI_is_inited());
+    if (SMPI_is_inited())
       SMPI_finalize();
 #endif
   }
index 146c978..89781bd 100644 (file)
@@ -22,6 +22,7 @@ VmFailureException::~VmFailureException()           = default;
 CancelException::~CancelException()                 = default;
 TracingError::~TracingError()                       = default;
 ParseError::~ParseError()                           = default;
+AssertionError::~AssertionError()                   = default;
 ForcefulKillException::~ForcefulKillException()     = default;
 
 void ForcefulKillException::do_throw()
index 87cfe01..f92ea49 100644 (file)
@@ -95,7 +95,6 @@ XBT_PRIVATE void smpi_cleanup_op_cost_callback();
 XBT_PRIVATE void smpi_comm_null_copy_buffer_callback(simgrid::kernel::activity::CommImpl* comm, void* buff,
                                                      size_t buff_size);
 
-XBT_PRIVATE int smpi_enabled();
 XBT_PRIVATE double smpi_mpi_wtime();
 XBT_PRIVATE void smpi_mpi_init();
 
index 03048a0..8b3a184 100644 (file)
@@ -213,10 +213,6 @@ void smpi_comm_null_copy_buffer_callback(simgrid::kernel::activity::CommImpl*, v
   /* nothing done in this version */
 }
 
-int smpi_enabled() {
-  return MPI_COMM_WORLD != MPI_COMM_UNINITIALIZED;
-}
-
 static void smpi_init_papi()
 {
 #if HAVE_PAPI
@@ -583,6 +579,11 @@ int smpi_main(const char* executable, int argc, char* argv[])
   return smpi_exit_status;
 }
 
+int SMPI_is_inited()
+{
+  return MPI_COMM_WORLD != MPI_COMM_UNINITIALIZED;
+}
+
 // Called either directly from the user code, or from the code called by smpirun
 void SMPI_init(){
   smpi_init_options_internal(false);
diff --git a/src/sthread/sthread.c b/src/sthread/sthread.c
new file mode 100644 (file)
index 0000000..666cb36
--- /dev/null
@@ -0,0 +1,216 @@
+/* SimGrid's pthread interposer. Redefinition of the pthread symbols (see the comment in sthread.h) */
+
+#define _GNU_SOURCE
+#include "src/sthread/sthread.h"
+#include <dlfcn.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+
+/* We don't want to intercept pthread within simgrid. Instead we should provide the real implem to simgrid */
+static int (*raw_pthread_create)(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*);
+static int (*raw_pthread_join)(pthread_t, void**);
+static int (*raw_mutex_init)(pthread_mutex_t*, const pthread_mutexattr_t*) = NULL;
+static int (*raw_mutex_lock)(pthread_mutex_t*)                             = NULL;
+static int (*raw_mutex_trylock)(pthread_mutex_t*)                          = NULL;
+static int (*raw_mutex_unlock)(pthread_mutex_t*)                           = NULL;
+static int (*raw_mutex_destroy)(pthread_mutex_t*)                          = NULL;
+static sem_t* (*raw_sem_open)(const char*, int)                            = NULL;
+static int (*raw_sem_init)(sem_t*, int, unsigned int)                      = NULL;
+static int (*raw_sem_wait)(sem_t*)                                         = NULL;
+static int (*raw_sem_post)(sem_t*)                                         = NULL;
+static void intercepter_init()
+{
+  raw_pthread_create = (typeof(raw_pthread_create))dlsym(RTLD_NEXT, "pthread_create");
+  raw_pthread_join   = (typeof(raw_pthread_join))dlsym(RTLD_NEXT, "pthread_join");
+  raw_mutex_init    = (int (*)(pthread_mutex_t*, const pthread_mutexattr_t*))dlsym(RTLD_NEXT, "pthread_mutex_init");
+  raw_mutex_lock    = (int (*)(pthread_mutex_t*))dlsym(RTLD_NEXT, "pthread_mutex_lock");
+  raw_mutex_trylock = (int (*)(pthread_mutex_t*))dlsym(RTLD_NEXT, "pthread_mutex_trylock");
+  raw_mutex_unlock  = (int (*)(pthread_mutex_t*))dlsym(RTLD_NEXT, "pthread_mutex_unlock");
+  raw_mutex_destroy = (int (*)(pthread_mutex_t*))dlsym(RTLD_NEXT, "pthread_mutex_destroy");
+
+  raw_sem_open = (sem_t * (*)(const char*, int)) dlsym(RTLD_NEXT, "sem_open");
+  raw_sem_init = (int (*)(sem_t*, int, unsigned int))dlsym(RTLD_NEXT, "sem_init");
+  raw_sem_wait = (int (*)(sem_t*))dlsym(RTLD_NEXT, "sem_wait");
+  raw_sem_post = (int (*)(sem_t*))dlsym(RTLD_NEXT, "sem_post");
+}
+
+static int sthread_inside_simgrid = 1;
+void sthread_enable(void)
+{ // Start intercepting all pthread calls
+  sthread_inside_simgrid = 0;
+}
+void sthread_disable(void)
+{ // Stop intercepting all pthread calls
+  sthread_inside_simgrid = 1;
+}
+int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg)
+{
+  if (raw_pthread_create == NULL)
+    intercepter_init();
+
+  if (sthread_inside_simgrid)
+    return raw_pthread_create(thread, attr, start_routine, arg);
+
+  sthread_inside_simgrid = 1;
+  int res                = sthread_create(thread, attr, start_routine, arg);
+  sthread_inside_simgrid = 0;
+  return res;
+}
+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);
+
+  sthread_inside_simgrid = 1;
+  int res                = sthread_join(thread, retval);
+  sthread_inside_simgrid = 0;
+  return res;
+}
+
+int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr)
+{
+  if (raw_mutex_init == NULL)
+    intercepter_init();
+
+  if (sthread_inside_simgrid)
+    return raw_mutex_init(mutex, attr);
+
+  sthread_inside_simgrid = 1;
+  int res                = sthread_mutex_init((sthread_mutex_t*)mutex, attr);
+  sthread_inside_simgrid = 0;
+  return res;
+}
+
+int pthread_mutex_lock(pthread_mutex_t* mutex)
+{
+  if (raw_mutex_lock == NULL)
+    intercepter_init();
+
+  if (sthread_inside_simgrid)
+    return raw_mutex_lock(mutex);
+
+  sthread_inside_simgrid = 1;
+  int res                = sthread_mutex_lock((sthread_mutex_t*)mutex);
+  sthread_inside_simgrid = 0;
+  return res;
+}
+
+int pthread_mutex_trylock(pthread_mutex_t* mutex)
+{
+  if (raw_mutex_trylock == NULL)
+    intercepter_init();
+
+  if (sthread_inside_simgrid)
+    return raw_mutex_trylock(mutex);
+
+  sthread_inside_simgrid = 1;
+  int res                = sthread_mutex_trylock((sthread_mutex_t*)mutex);
+  sthread_inside_simgrid = 0;
+  return res;
+}
+
+int pthread_mutex_unlock(pthread_mutex_t* mutex)
+{
+  if (raw_mutex_unlock == NULL)
+    intercepter_init();
+
+  if (sthread_inside_simgrid)
+    return raw_mutex_unlock(mutex);
+
+  sthread_inside_simgrid = 1;
+  int res                = sthread_mutex_unlock((sthread_mutex_t*)mutex);
+  sthread_inside_simgrid = 0;
+  return res;
+}
+int pthread_mutex_destroy(pthread_mutex_t* mutex)
+{
+  if (raw_mutex_destroy == NULL)
+    intercepter_init();
+
+  if (sthread_inside_simgrid)
+    return raw_mutex_destroy(mutex);
+
+  sthread_inside_simgrid = 1;
+  int res                = sthread_mutex_destroy((sthread_mutex_t*)mutex);
+  sthread_inside_simgrid = 0;
+  return res;
+}
+
+#if 0
+int sem_init(sem_t *sem, int pshared, unsigned int value) {
+       int res;
+
+       res=raw_sem_init(sem,pshared,value);
+       return res;
+}
+
+int sem_wait(sem_t *sem) {
+       int res;
+
+       res = raw_sem_wait(sem);
+       return res;
+}
+
+int sem_post(sem_t *sem) {
+       return raw_sem_post(sem);
+}
+
+int pthread_join(pthread_t thread, void **retval) {
+       sg_actor_join(thread, -1);
+    return 0;
+}
+
+int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr) {
+    *cond = sg_cond_init();
+    return 0;
+}
+
+int pthread_cond_signal(pthread_cond_t *cond) {
+       sg_cond_notify_one(*cond);
+    return 0;
+}
+
+int pthread_cond_broadcast(pthread_cond_t *cond) {
+       sg_cond_notify_all(*cond);
+    return 0;
+}
+
+int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) {
+       sg_cond_wait(*cond, *mutex);
+    return 0;
+}
+
+int pthread_cond_destroy(pthread_cond_t *cond) {
+       sg_cond_destroy(*cond);
+    return 0;
+}
+#endif
+
+/* Trampoline for the real main() */
+static int (*raw_main)(int, char**, char**);
+
+/* Our fake main() that gets called by __libc_start_main() */
+static int main_hook(int argc, char** argv, char** envp)
+{
+  return sthread_main(argc, argv, envp, raw_main);
+}
+
+/* Wrapper for __libc_start_main() that replaces the real main function with our hooked version. */
+int __libc_start_main(int (*main)(int, char**, char**), int argc, char** argv, int (*init)(int, char**, char**),
+                      void (*fini)(void), void (*rtld_fini)(void), void* stack_end);
+
+int __libc_start_main(int (*main)(int, char**, char**), int argc, char** argv, int (*init)(int, char**, char**),
+                      void (*fini)(void), void (*rtld_fini)(void), void* stack_end)
+{
+  /* Save the real main function address */
+  raw_main = main;
+
+  /* Find the real __libc_start_main()... */
+  typeof(&__libc_start_main) orig = dlsym(RTLD_NEXT, "__libc_start_main");
+  /* ... and call it with our custom main function */
+  return orig(main_hook, argc, argv, init, fini, rtld_fini, stack_end);
+}
diff --git a/src/sthread/sthread.h b/src/sthread/sthread.h
new file mode 100644 (file)
index 0000000..9bc6c50
--- /dev/null
@@ -0,0 +1,45 @@
+/* SimGrid's pthread interposer. Intercepts most of the pthread and semaphore calls to model-check them.
+ *
+ * Intercepting on pthread is somewhat complicated by the fact that pthread is used everywhere in the system headers.
+ * To reduce definition conflicts, our redefinitions of the pthread symbols (in sthread.c) load as little headers as
+ * possible. Thus, the actual implementations are separated in another file (sthread_impl.cpp) and are used as black
+ * boxes by our redefinitions.
+ *
+ * The sthread_* symbols are those actual implementations, used in the pthread_* redefinitions. */
+
+#ifndef SIMGRID_STHREAD_H
+#define SIMGRID_STHREAD_H
+
+#if defined(__ELF__)
+#define XBT_PUBLIC __attribute__((visibility("default")))
+#else
+#define XBT_PUBLIC
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+// Launch the simulation. The old main function (passed as a parameter) is launched as an actor
+int sthread_main(int argc, char** argv, char** envp, int (*raw_main)(int, char**, char**));
+XBT_PUBLIC void sthread_enable(void);  // Start intercepting all pthread calls
+XBT_PUBLIC void sthread_disable(void); // Stop intercepting all pthread calls
+
+typedef unsigned long int sthread_t;
+int sthread_create(sthread_t* thread, const /*pthread_attr_t*/ void* attr, void* (*start_routine)(void*), void* arg);
+int sthread_join(sthread_t thread, void** retval);
+
+typedef struct {
+  void* mutex;
+} sthread_mutex_t;
+int sthread_mutex_init(sthread_mutex_t* mutex, const /*pthread_mutexattr_t*/ void* attr);
+int sthread_mutex_lock(sthread_mutex_t* mutex);
+int sthread_mutex_trylock(sthread_mutex_t* mutex);
+int sthread_mutex_unlock(sthread_mutex_t* mutex);
+int sthread_mutex_destroy(sthread_mutex_t* mutex);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/src/sthread/sthread_impl.cpp b/src/sthread/sthread_impl.cpp
new file mode 100644 (file)
index 0000000..df18541
--- /dev/null
@@ -0,0 +1,174 @@
+/* SimGrid's pthread interposer. Actual implementation of the symbols (see the comment in sthread.h) */
+
+#include "smpi/smpi.h"
+#include <simgrid/actor.h>
+#include <simgrid/s4u/Actor.hpp>
+#include <simgrid/s4u/Engine.hpp>
+#include <simgrid/s4u/Mutex.hpp>
+#include <simgrid/s4u/NetZone.hpp>
+#include <xbt/base.h>
+#include <xbt/sysdep.h>
+
+#include "src/internal_config.h"
+#include "src/sthread/sthread.h"
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <sstream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <thread>
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(sthread, "pthread intercepter");
+namespace sg4 = simgrid::s4u;
+
+static sg4::Host* lilibeth = nullptr;
+
+int sthread_main(int argc, char** argv, char** envp, int (*raw_main)(int, char**, char**))
+{
+  std::ostringstream id;
+  id << std::this_thread::get_id();
+
+  XBT_DEBUG("sthread main() is starting in thread %s", id.str().c_str());
+
+  sg4::Engine e(&argc, argv);
+  auto* zone = sg4::create_full_zone("world");
+  lilibeth   = zone->create_host("Lilibeth", 1e15);
+  zone->seal();
+
+  /* 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);
+
+  XBT_INFO("Starting the simulation.");
+  sg4::Engine::get_instance()->run();
+  sthread_disable();
+  XBT_INFO("All threads exited. Terminating the simulation.");
+
+  return 0;
+}
+
+struct sthread_mutex {
+  s4u_Mutex* mutex;
+};
+
+static void thread_create_wrapper(void* (*user_function)(void*), void* param)
+{
+#if HAVE_SMPI
+  if (SMPI_is_inited())
+    SMPI_thread_create();
+#endif
+  sthread_enable();
+  user_function(param);
+  sthread_disable();
+}
+
+int sthread_create(unsigned long int* thread, const void* /*pthread_attr_t* attr*/, void* (*start_routine)(void*),
+                   void* arg)
+{
+  static int TID = 0;
+  TID++;
+  XBT_VERB("Create thread %d", TID);
+  int rank = 0;
+#if HAVE_SMPI
+  if (SMPI_is_inited())
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+#endif
+  std::string name    = simgrid::xbt::string_printf("%d:%d", rank, TID);
+  sg4::ActorPtr actor = sg4::Actor::init(name.c_str(), lilibeth);
+  actor->start(thread_create_wrapper, start_routine, arg);
+
+  intrusive_ptr_add_ref(actor.get());
+  *thread = reinterpret_cast<unsigned long>(actor.get());
+  return 0;
+}
+int sthread_join(sthread_t thread, void** /*retval*/)
+{
+  sg4::ActorPtr actor(reinterpret_cast<sg4::Actor*>(thread));
+  actor->join();
+  intrusive_ptr_release(actor.get());
+
+  return 0;
+}
+
+int sthread_mutex_init(sthread_mutex_t* mutex, const void* /*pthread_mutexattr_t* attr*/)
+{
+  auto m = sg4::Mutex::create();
+  intrusive_ptr_add_ref(m.get());
+
+  mutex->mutex = m.get();
+  return 0;
+}
+
+int sthread_mutex_lock(sthread_mutex_t* mutex)
+{
+  static_cast<sg4::Mutex*>(mutex->mutex)->lock();
+  return 0;
+}
+
+int sthread_mutex_trylock(sthread_mutex_t* mutex)
+{
+  return static_cast<sg4::Mutex*>(mutex->mutex)->try_lock();
+}
+
+int sthread_mutex_unlock(sthread_mutex_t* mutex)
+{
+  static_cast<sg4::Mutex*>(mutex->mutex)->unlock();
+  return 0;
+}
+int sthread_mutex_destroy(sthread_mutex_t* mutex)
+{
+  intrusive_ptr_release(static_cast<sg4::Mutex*>(mutex->mutex));
+  return 0;
+}
+
+#if 0
+int sem_init(sem_t *sem, int pshared, unsigned int value) {
+       int res;
+
+       res=raw_sem_init(sem,pshared,value);
+       return res;
+}
+
+int sem_wait(sem_t *sem) {
+       int res;
+
+       res = raw_sem_wait(sem);
+       return res;
+}
+
+int sem_post(sem_t *sem) {
+       return raw_sem_post(sem);
+}
+
+int pthread_join(pthread_t thread, void **retval) {
+       sg_actor_join(thread, -1);
+    return 0;
+}
+
+int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr) {
+    *cond = sg_cond_init();
+    return 0;
+}
+
+int pthread_cond_signal(pthread_cond_t *cond) {
+       sg_cond_notify_one(*cond);
+    return 0;
+}
+
+int pthread_cond_broadcast(pthread_cond_t *cond) {
+       sg_cond_notify_all(*cond);
+    return 0;
+}
+
+int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) {
+       sg_cond_wait(*cond, *mutex);
+    return 0;
+}
+
+int pthread_cond_destroy(pthread_cond_t *cond) {
+       sg_cond_destroy(*cond);
+    return 0;
+}
+#endif
index ef5b9f6..82b2f92 100644 (file)
@@ -7,6 +7,7 @@
 #include <simgrid/s4u/Engine.hpp>
 #include <simgrid/s4u/Host.hpp>
 
+#include "xbt/asserts.hpp"
 #include "src/kernel/EngineImpl.hpp"
 #include "src/kernel/resource/VirtualMachineImpl.hpp"
 
@@ -28,7 +29,7 @@ namespace simgrid::kernel::resource {
  ************/
 HostImpl::HostImpl(const std::string& name) : piface_(this), name_(name)
 {
-  xbt_assert(s4u::Host::by_name_or_null(name_) == nullptr, "Refusing to create a second host named '%s'.", get_cname());
+  xbt_enforce(s4u::Host::by_name_or_null(name_) == nullptr, "Refusing to create a second host named '%s'.", get_cname());
 }
 
 HostImpl::~HostImpl()
index 065f79a..8ee72a4 100644 (file)
@@ -10,6 +10,7 @@
 #include "simgrid/config.h"
 #include "simgrid/sg_config.hpp"
 #include "src/internal_config.h"
+#include "src/sthread/sthread.h" // sthread_inside_simgrid
 #include "xbt/config.hpp"
 #include "xbt/coverage.h"
 #include "xbt/dynar.h"
@@ -40,6 +41,7 @@ std::string binary_name;          /* Name of the system process containing us (m
 std::vector<std::string> cmdline; /* all we got in argv */
 } // namespace simgrid::xbt
 
+
 int xbt_initialized = 0;
 simgrid::config::Flag<bool> cfg_dbg_clean_atexit{
     "debug/clean-atexit",
@@ -54,6 +56,12 @@ int xbt_pagebits = 0;
  */
 static void xbt_preinit() XBT_ATTRIB_CONSTRUCTOR(200);
 static void xbt_postexit();
+void sthread_enable()
+{ // These symbols are used from ContextSwapped in any case, but they are only useful
+}
+void sthread_disable()
+{ //  when libsthread is LD_PRELOADED. In this case, sthread's implem gets used instead.
+}
 
 #ifdef _WIN32
 #include <windows.h>
@@ -157,3 +165,10 @@ void xbt_abort()
 #endif
   abort();
 }
+
+#ifndef HAVE_SMPI
+int SMPI_is_inited()
+{
+  return false;
+}
+#endif
index 75b0c8b..6333844 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <simgrid/s4u.hpp>
 #include <vector>
+#include <iostream>
 
 static void runner()
 {
@@ -30,10 +31,14 @@ int main(int argc, char* argv[])
              argv[0], argv[0]);
 
   const char* platform_file = argv[1];
-  e.load_platform(platform_file);
 
-  simgrid::s4u::Actor::create("actor", e.host_by_name("c1_0"), runner);
+  try {
+    e.load_platform(platform_file);
+    simgrid::s4u::Actor::create("actor", e.host_by_name("c1_0"), runner);
+    e.run();
+  } catch (const simgrid::AssertionError& e) {
+    std::cout << e.what() << "\n";
+  }
 
-  e.run();
   return 0;
 }
index 18a7cca..356449e 100644 (file)
@@ -1,5 +1,4 @@
-! expect signal SIGIOT
 $ $VALGRIND_NO_LEAK_CHECK ${bindir:=.}/issue71 ${srcdir:=.}/platform_bad.xml "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n" --log=no_loc
 > [  0.000000] (0:maestro@) Configuration change: Set 'host/model' to 'ptask_L07'
 > [  0.000000] (0:maestro@) Switching to the L07 model to handle parallel tasks.
-> [  0.000000] (0:maestro@) Invalid NetzoneRoute from cluster1@router_c2 to cluster2@router_c1: gw_src router_c2 belongs to cluster2, not to cluster1.
+> Invalid NetzoneRoute from cluster1@router_c2 to cluster2@router_c1: gw_src router_c2 belongs to cluster2, not to cluster1.
index 97661ce..2fbe539 100644 (file)
@@ -248,6 +248,11 @@ set(SMPI_SRC
   src/surf/network_ib.cpp
   src/surf/network_smpi.cpp
   )
+set(STHREAD_SRC
+  src/sthread/sthread_impl.cpp
+  src/sthread/sthread.c
+  src/sthread/sthread.h
+)
 
 set(XBT_SRC
   src/xbt/OsSemaphore.hpp
@@ -732,6 +737,7 @@ set(headers_to_install
   include/smpi/forward.hpp
   include/xbt.h
   include/xbt/asserts.h
+  include/xbt/asserts.hpp
   include/xbt/automaton.h
   include/xbt/automaton.hpp
   include/xbt/backtrace.hpp
@@ -1030,6 +1036,7 @@ set(CMAKEFILES_TXT
   examples/smpi/replay_multiple/CMakeLists.txt
   examples/smpi/replay_multiple_manual_deploy/CMakeLists.txt
   examples/smpi/smpi_s4u_masterworker/CMakeLists.txt
+  examples/sthread/CMakeLists.txt
 
   teshsuite/java/CMakeLists.txt
   teshsuite/kernel/CMakeLists.txt
index 47e8911..8d871e3 100644 (file)
@@ -111,6 +111,7 @@ set(source_to_pack
   ${TRACING_SRC}
   ${XBT_RL_SRC}
   ${XBT_SRC}
+  ${STHREAD_SRC}
   ${EXTRA_DIST}
   ${CMAKE_SOURCE_FILES}
   ${CMAKEFILES_TXT}
index 8729e1c..b0b8837 100644 (file)
@@ -26,6 +26,15 @@ set_property(TARGET simgrid
 
 add_dependencies(simgrid maintainer_files)
 
+if("${CMAKE_SYSTEM}" MATCHES "Linux")
+  add_library(sthread SHARED ${STHREAD_SRC})
+  set_property(TARGET sthread
+                APPEND PROPERTY INCLUDE_DIRECTORIES "${INTERNAL_INCLUDES}")
+  target_link_libraries(sthread simgrid)
+else()
+  set(EXTRA_DIST ${EXTRA_DIST} ${STHREAD_SRC})
+endif()
+
 if(enable_model-checking)
   add_executable(simgrid-mc ${MC_SIMGRID_MC_SRC})
   target_link_libraries(simgrid-mc simgrid)
@@ -36,9 +45,11 @@ if(enable_model-checking)
   install(TARGETS simgrid-mc # install that binary without breaking the rpath on Mac
     RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}/)
   add_dependencies(tests-mc simgrid-mc)
+  if("${CMAKE_SYSTEM}" MATCHES "Linux")
+    add_dependencies(tests-mc sthread)
+  endif()
 endif()
 
-
 # Compute the dependencies of SimGrid
 #####################################
 # search for dlopen