X-Git-Url: http://bilbo.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/7a1d9713c8dd8a96686f75acb428b2e4dcb08c1f..dd49f9d0ff63334f76e12446cd8076edef85c508:/src/mc/remote/AppSide.cpp diff --git a/src/mc/remote/AppSide.cpp b/src/mc/remote/AppSide.cpp index 9efa3081d6..39326a0a22 100644 --- a/src/mc/remote/AppSide.cpp +++ b/src/mc/remote/AppSide.cpp @@ -11,7 +11,10 @@ #include "src/kernel/actor/SimcallObserver.hpp" #include "src/mc/mc_base.hpp" #include "src/mc/mc_config.hpp" +#include "src/mc/mc_environ.h" +#if SIMGRID_HAVE_STATEFUL_MC #include "src/mc/sosp/RemoteProcessMemory.hpp" +#endif #if HAVE_SMPI #include "src/smpi/include/private.hpp" #endif @@ -21,6 +24,7 @@ #include #include +#include #include // setvbuf #include #include @@ -38,16 +42,18 @@ namespace simgrid::mc { std::unique_ptr AppSide::instance_; -AppSide* AppSide::initialize() +AppSide* AppSide::get() { - if (not std::getenv(MC_ENV_SOCKET_FD)) // We are not in MC mode: don't initialize the MC world + // Only initialize the MC world once + if (instance_ != nullptr) + return instance_.get(); + + if (std::getenv(MC_ENV_SOCKET_FD) == nullptr) // We are not in MC mode: don't initialize the MC world return nullptr; - // Do not break if we are called multiple times: - if (instance_) - return instance_.get(); + XBT_DEBUG("Initialize the MC world. %s=%s", MC_ENV_NEED_PTRACE, std::getenv(MC_ENV_NEED_PTRACE)); - simgrid::mc::model_checking_mode = ModelCheckingMode::APP_SIDE; + simgrid::mc::set_model_checking_mode(ModelCheckingMode::APP_SIDE); setvbuf(stdout, nullptr, _IOLBF, 0); @@ -56,17 +62,10 @@ AppSide* AppSide::initialize() int fd = xbt_str_parse_int(fd_env, "Not a number in variable '" MC_ENV_SOCKET_FD "'"); XBT_DEBUG("Model-checked application found socket FD %i", fd); - // Check the socket type/validity: - int type; - socklen_t socklen = sizeof(type); - xbt_assert(getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &socklen) == 0, "Could not check socket type"); - xbt_assert(type == SOCK_SEQPACKET, "Unexpected socket type %i", type); - XBT_DEBUG("Model-checked application found expected socket type"); - instance_ = std::make_unique(fd); // Wait for the model-checker: - if (getenv("MC_NEED_PTRACE") != nullptr) { + if (getenv(MC_ENV_NEED_PTRACE) != nullptr) { errno = 0; #if defined __linux__ ptrace(PTRACE_TRACEME, 0, nullptr, nullptr); @@ -102,7 +101,7 @@ void AppSide::handle_deadlock_check(const s_mc_message_t*) const s_mc_message_int_t answer = {}; answer.type = MessageType::DEADLOCK_CHECK_REPLY; answer.value = deadlock; - xbt_assert(channel_.send(answer) == 0, "Could not send response"); + xbt_assert(channel_.send(answer) == 0, "Could not send response: %s", strerror(errno)); } void AppSide::handle_simcall_execute(const s_mc_message_simcall_execute_t* message) const { @@ -112,7 +111,8 @@ void AppSide::handle_simcall_execute(const s_mc_message_simcall_execute_t* messa // The client may send some messages to the server while processing the transition actor->simcall_handle(message->times_considered_); // Say the server that the transition is over and that it should proceed - xbt_assert(channel_.send(MessageType::WAITING) == 0, "Could not send MESSAGE_WAITING to model-checker"); + xbt_assert(channel_.send(MessageType::WAITING) == 0, "Could not send MESSAGE_WAITING to model-checker: %s", + strerror(errno)); // Finish the RPC from the server: return a serialized observer, to build a Transition on Checker side s_mc_message_simcall_execute_answer_t answer = {}; @@ -130,7 +130,7 @@ void AppSide::handle_simcall_execute(const s_mc_message_simcall_execute_t* messa answer.buffer.back() = '\0'; XBT_DEBUG("send SIMCALL_EXECUTE_ANSWER(%s) ~> '%s'", actor->get_cname(), str.c_str()); - xbt_assert(channel_.send(answer) == 0, "Could not send response"); + xbt_assert(channel_.send(answer) == 0, "Could not send response: %s", strerror(errno)); } void AppSide::handle_finalize(const s_mc_message_int_t* msg) const @@ -147,26 +147,37 @@ void AppSide::handle_finalize(const s_mc_message_int_t* msg) const #endif } coverage_checkpoint(); - xbt_assert(channel_.send(MessageType::FINALIZE_REPLY) == 0, "Could not answer to FINALIZE"); + xbt_assert(channel_.send(MessageType::FINALIZE_REPLY) == 0, "Could not answer to FINALIZE: %s", strerror(errno)); std::fflush(stdout); if (terminate_asap) ::_Exit(0); } -void AppSide::handle_fork(const s_mc_message_int_t* msg) +void AppSide::handle_fork(const s_mc_message_fork_t* msg) { - int pid = fork(); + int status; + int pid; + /* Reap any zombie child, saving its status for later use in AppSide::handle_wait_child() */ + while ((pid = waitpid(-1, &status, WNOHANG)) > 0) + child_statuses_[pid] = status; + + pid = fork(); xbt_assert(pid >= 0, "Could not fork application sub-process: %s.", strerror(errno)); if (pid == 0) { // Child - int sock = socket(AF_LOCAL, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); + int sock = socket(AF_UNIX, +#ifdef __APPLE__ + SOCK_STREAM, /* Mac OSX does not have AF_UNIX + SOCK_SEQPACKET, even if that's faster*/ +#else + SOCK_SEQPACKET, +#endif + 0); struct sockaddr_un addr = {}; - addr.sun_family = AF_LOCAL; - snprintf(addr.sun_path, 64, "/tmp/simgrid-mc-%lu", msg->value); - auto addr_size = offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path); + addr.sun_family = AF_UNIX; + std::copy_n(begin(msg->socket_name), MC_SOCKET_NAME_LEN, addr.sun_path); - xbt_assert(connect(sock, (struct sockaddr*)&addr, addr_size) >= 0, - "Cannot connect to Checker on /tmp/simgrid-mc-%lu: %s.", msg->value, strerror(errno)); + xbt_assert(connect(sock, (struct sockaddr*)&addr, sizeof addr) >= 0, "Cannot connect to Checker on %c%s: %s.", + (addr.sun_path[0] ? addr.sun_path[0] : '@'), addr.sun_path + 1, strerror(errno)); channel_.reset_socket(sock); @@ -174,13 +185,20 @@ void AppSide::handle_fork(const s_mc_message_int_t* msg) answer.type = MessageType::FORK_REPLY; answer.value = getpid(); xbt_assert(channel_.send(answer) == 0, "Could not send response to WAIT_CHILD_REPLY: %s", strerror(errno)); + } else { + XBT_VERB("App %d forks subprocess %d.", getpid(), pid); } } void AppSide::handle_wait_child(const s_mc_message_int_t* msg) { int status; errno = 0; - waitpid(msg->value, &status, 0); + if (auto search = child_statuses_.find(msg->value); search != child_statuses_.end()) { + status = search->second; + child_statuses_.erase(search); // We only need this info once + } else { + waitpid(msg->value, &status, 0); + } xbt_assert(errno == 0, "Cannot wait on behalf of the checker: %s.", strerror(errno)); s_mc_message_int_t answer = {}; @@ -190,12 +208,12 @@ void AppSide::handle_wait_child(const s_mc_message_int_t* msg) } void AppSide::handle_need_meminfo() { -#if SIMGRID_HAVE_MC +#if SIMGRID_HAVE_STATEFUL_MC this->need_memory_info_ = true; s_mc_message_need_meminfo_reply_t answer = {}; answer.type = MessageType::NEED_MEMINFO_REPLY; answer.mmalloc_default_mdp = mmalloc_get_current_heap(); - xbt_assert(channel_.send(answer) == 0, "Could not send response to the request for meminfo."); + xbt_assert(channel_.send(answer) == 0, "Could not send response to the request for meminfo: %s", strerror(errno)); #else xbt_die("SimGrid was compiled without MC suppport, so liveness and similar features are not available."); #endif @@ -219,18 +237,15 @@ void AppSide::handle_actors_status() const answer.type = MessageType::ACTORS_STATUS_REPLY_COUNT; answer.count = static_cast(status.size()); - xbt_assert(channel_.send(answer) == 0, "Could not send ACTORS_STATUS_REPLY msg"); + xbt_assert(channel_.send(answer) == 0, "Could not send ACTORS_STATUS_REPLY msg: %s", strerror(errno)); if (answer.count > 0) { size_t size = status.size() * sizeof(s_mc_message_actors_status_one_t); - xbt_assert(channel_.send(status.data(), size) == 0, "Could not send ACTORS_STATUS_REPLY data"); + xbt_assert(channel_.send(status.data(), size) == 0, "Could not send ACTORS_STATUS_REPLY data: %s", strerror(errno)); } // Serialize each transition to describe what each actor is doing XBT_DEBUG("Deliver ACTOR_TRANSITION_PROBE payload"); for (const auto& actor_status : status) { - if (not actor_status.enabled) - continue; - const auto& actor = actor_list.at(actor_status.aid); const int max_considered = actor_status.max_considered; @@ -252,7 +267,7 @@ void AppSide::handle_actors_status() const strncpy(probe.buffer.data(), str.c_str(), probe.buffer.size() - 1); probe.buffer.back() = '\0'; - xbt_assert(channel_.send(probe) == 0, "Could not send ACTOR_TRANSITION_PROBE payload"); + xbt_assert(channel_.send(probe) == 0, "Could not send ACTOR_TRANSITION_PROBE payload: %s", strerror(errno)); } // NOTE: We do NOT need to reset `times_considered` for each actor's // simcall observer here to the "original" value (i.e. the value BEFORE @@ -266,7 +281,7 @@ void AppSide::handle_actors_maxpid() const s_mc_message_int_t answer = {}; answer.type = MessageType::ACTORS_MAXPID_REPLY; answer.value = kernel::actor::ActorImpl::get_maxpid(); - xbt_assert(channel_.send(answer) == 0, "Could not send response"); + xbt_assert(channel_.send(answer) == 0, "Could not send response: %s", strerror(errno)); } #define assert_msg_size(_name_, _type_) \ @@ -285,7 +300,7 @@ void AppSide::handle_messages() XBT_DEBUG("Socket closed on the Checker side, bailing out."); ::_Exit(0); // Nobody's listening to that process anymore => exit as quickly as possible. } - xbt_assert(received_size >= 0, "Could not receive commands from the model-checker"); + xbt_assert(received_size >= 0, "Could not receive commands from the model-checker: %s", strerror(errno)); xbt_assert(static_cast(received_size) >= sizeof(s_mc_message_t), "Cannot handle short message (size=%zd)", received_size); @@ -311,8 +326,8 @@ void AppSide::handle_messages() break; case MessageType::FORK: - assert_msg_size("FORK", s_mc_message_int_t); - handle_fork((s_mc_message_int_t*)message_buffer.data()); + assert_msg_size("FORK", s_mc_message_fork_t); + handle_fork((s_mc_message_fork_t*)message_buffer.data()); break; case MessageType::WAIT_CHILD: @@ -353,14 +368,16 @@ void AppSide::main_loop() sthread_enable(); while (true) { simgrid::mc::execute_actors(); - xbt_assert(channel_.send(MessageType::WAITING) == 0, "Could not send WAITING message to model-checker"); + xbt_assert(channel_.send(MessageType::WAITING) == 0, "Could not send WAITING message to model-checker: %s", + strerror(errno)); this->handle_messages(); } } void AppSide::report_assertion_failure() { - xbt_assert(channel_.send(MessageType::ASSERTION_FAILED) == 0, "Could not send assertion to model-checker"); + xbt_assert(channel_.send(MessageType::ASSERTION_FAILED) == 0, "Could not send assertion to model-checker: %s", + strerror(errno)); this->handle_messages(); } @@ -369,12 +386,12 @@ void AppSide::ignore_memory(void* addr, std::size_t size) const if (not MC_is_active() || not need_memory_info_) return; -#if SIMGRID_HAVE_MC +#if SIMGRID_HAVE_STATEFUL_MC s_mc_message_ignore_memory_t message = {}; message.type = MessageType::IGNORE_MEMORY; message.addr = (std::uintptr_t)addr; message.size = size; - xbt_assert(channel_.send(message) == 0, "Could not send IGNORE_MEMORY message to model-checker"); + xbt_assert(channel_.send(message) == 0, "Could not send IGNORE_MEMORY message to model-checker: %s", strerror(errno)); #else xbt_die("Cannot really call ignore_heap() in non-SIMGRID_MC mode."); #endif @@ -385,7 +402,7 @@ void AppSide::ignore_heap(void* address, std::size_t size) const if (not MC_is_active() || not need_memory_info_) return; -#if SIMGRID_HAVE_MC +#if SIMGRID_HAVE_STATEFUL_MC const s_xbt_mheap_t* heap = mmalloc_get_current_heap(); s_mc_message_ignore_heap_t message = {}; @@ -401,7 +418,7 @@ void AppSide::ignore_heap(void* address, std::size_t size) const heap->heapinfo[message.block].busy_frag.ignore[message.fragment]++; } - xbt_assert(channel_.send(message) == 0, "Could not send ignored region to MCer"); + xbt_assert(channel_.send(message) == 0, "Could not send ignored region to MCer: %s", strerror(errno)); #else xbt_die("Cannot really call ignore_heap() in non-SIMGRID_MC mode."); #endif @@ -412,12 +429,12 @@ void AppSide::unignore_heap(void* address, std::size_t size) const if (not MC_is_active() || not need_memory_info_) return; -#if SIMGRID_HAVE_MC +#if SIMGRID_HAVE_STATEFUL_MC s_mc_message_ignore_memory_t message = {}; message.type = MessageType::UNIGNORE_HEAP; message.addr = (std::uintptr_t)address; message.size = size; - xbt_assert(channel_.send(message) == 0, "Could not send IGNORE_HEAP message to model-checker"); + xbt_assert(channel_.send(message) == 0, "Could not send IGNORE_HEAP message to model-checker: %s", strerror(errno)); #else xbt_die("Cannot really call unignore_heap() in non-SIMGRID_MC mode."); #endif @@ -430,14 +447,14 @@ void AppSide::declare_symbol(const char* name, int* value) const return; } -#if SIMGRID_HAVE_MC +#if SIMGRID_HAVE_STATEFUL_MC s_mc_message_register_symbol_t message = {}; message.type = MessageType::REGISTER_SYMBOL; xbt_assert(strlen(name) + 1 <= message.name.size(), "Symbol is too long"); strncpy(message.name.data(), name, message.name.size() - 1); message.callback = nullptr; message.data = value; - xbt_assert(channel_.send(message) == 0, "Could send REGISTER_SYMBOL message to model-checker"); + xbt_assert(channel_.send(message) == 0, "Could send REGISTER_SYMBOL message to model-checker: %s", strerror(errno)); #else xbt_die("Cannot really call declare_symbol() in non-SIMGRID_MC mode."); #endif @@ -449,12 +466,13 @@ void AppSide::declare_symbol(const char* name, int* value) const * when we analyze/compare the content of the heap so it must be told where * they are with this function. */ +#if HAVE_UCONTEXT_H /* Apple don't want us to use ucontexts */ void AppSide::declare_stack(void* stack, size_t size, ucontext_t* context) const { if (not MC_is_active() || not need_memory_info_) return; -#if SIMGRID_HAVE_MC +#if SIMGRID_HAVE_STATEFUL_MC const s_xbt_mheap_t* heap = mmalloc_get_current_heap(); s_stack_region_t region = {}; @@ -466,9 +484,11 @@ void AppSide::declare_stack(void* stack, size_t size, ucontext_t* context) const s_mc_message_stack_region_t message = {}; message.type = MessageType::STACK_REGION; message.stack_region = region; - xbt_assert(channel_.send(message) == 0, "Could not send STACK_REGION to model-checker"); + xbt_assert(channel_.send(message) == 0, "Could not send STACK_REGION to model-checker: %s", strerror(errno)); #else xbt_die("Cannot really call declare_stack() in non-SIMGRID_MC mode."); #endif } +#endif + } // namespace simgrid::mc