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):
- 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
(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
----------------------------------------------------------------------------
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
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
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
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
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
$ 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
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)
--- /dev/null
+# 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()
--- /dev/null
+#!/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!
--- /dev/null
+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)
+
+
--- /dev/null
+/* 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;
+}
--- /dev/null
+$ ./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
--- /dev/null
+/* 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;
+}
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 {
SG_ERROR_VM
} sg_error_t;
+XBT_PUBLIC int SMPI_is_inited();
+
#endif /* SIMGRID_TYPES_H */
--- /dev/null
+/* 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
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.")
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"))
"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,
"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",
} 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
#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>
void Context::stop()
{
this->actor_->cleanup_from_self();
+ sthread_disable();
throw ForcefulKillException(); // clean RAII variables with the dedicated exception
}
AttachContext::~AttachContext() = default;
#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"
__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;
}
// 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);
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_;
}
}
#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"
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();
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());
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);
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));
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();
}
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);
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();
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);
}
}
// 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()) {
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());
}
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;
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;
}
}
/* 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 */
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) {
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_)
#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");
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;
}
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());
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());
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_++;
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; }
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
}
CancelException::~CancelException() = default;
TracingError::~TracingError() = default;
ParseError::~ParseError() = default;
+AssertionError::~AssertionError() = default;
ForcefulKillException::~ForcefulKillException() = default;
void ForcefulKillException::do_throw()
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();
/* nothing done in this version */
}
-int smpi_enabled() {
- return MPI_COMM_WORLD != MPI_COMM_UNINITIALIZED;
-}
-
static void smpi_init_papi()
{
#if HAVE_PAPI
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);
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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
#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"
************/
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()
#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"
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",
*/
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>
#endif
abort();
}
+
+#ifndef HAVE_SMPI
+int SMPI_is_inited()
+{
+ return false;
+}
+#endif
#include <simgrid/s4u.hpp>
#include <vector>
+#include <iostream>
static void runner()
{
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;
}
-! 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.
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
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
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
${TRACING_SRC}
${XBT_RL_SRC}
${XBT_SRC}
+ ${STHREAD_SRC}
${EXTRA_DIST}
${CMAKE_SOURCE_FILES}
${CMAKEFILES_TXT}
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)
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