From 67634e9178fa9195d4b6fffb61e86ccd81a783d9 Mon Sep 17 00:00:00 2001 From: Martin Quinson Date: Fri, 10 Mar 2017 23:09:29 +0100 Subject: [PATCH] Allow to mark actors as daemon Daemon actors are automatically killed when the last non-daemon terminates --- ChangeLog | 4 +- examples/msg/CMakeLists.txt | 4 +- examples/msg/process-daemon/process-daemon.c | 49 +++++++++++++++++++ .../msg/process-daemon/process-daemon.tesh | 11 +++++ include/simgrid/msg.h | 1 + src/msg/msg_process.cpp | 12 ++++- src/simix/ActorImpl.cpp | 29 +++++++++++ src/simix/ActorImpl.hpp | 4 ++ src/simix/smx_global.cpp | 10 +++- src/simix/smx_private.h | 2 + 10 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 examples/msg/process-daemon/process-daemon.c create mode 100644 examples/msg/process-daemon/process-daemon.tesh diff --git a/ChangeLog b/ChangeLog index 34328602e5..77ee0e4883 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,7 +10,9 @@ SimGrid (3.15) UNRELEASED; urgency=low That's a point in the routing algorithm, let's avoid wrong simplifications. MSG - - New function: MSG_process_yield() + - New: MSG_process_yield() + - New: MSG_process_daemon(). Daemon processes are automatically killed + when the last non-daemon process terminates - Renamed MSG_energy_plugin_init() -> MSG_host_energy_plugin_init() to make room for the upcoming network energy plugin. diff --git a/examples/msg/CMakeLists.txt b/examples/msg/CMakeLists.txt index a427f2dbe5..f25ab08c84 100644 --- a/examples/msg/CMakeLists.txt +++ b/examples/msg/CMakeLists.txt @@ -2,7 +2,7 @@ foreach(x actions-comm actions-storage app-masterworker app-pingpong app-pmm app-token-ring async-yield async-wait async-waitall async-waitany cloud-capping cloud-masterworker cloud-migration cloud-simple cloud-two-tasks dht-chord dht-pastry energy-consumption energy-onoff energy-pstate energy-ptask energy-vm platform-failures - io-file io-remote io-storage task-priority process-create process-kill process-migration process-suspend + io-file io-remote io-storage task-priority process-create process-daemon process-kill process-migration process-suspend platform-properties process-startkilltime synchro-semaphore trace-categories trace-route-user-variables trace-link-user-variables trace-masterworker trace-platform trace-process-migration trace-host-user-variables) @@ -96,7 +96,7 @@ set(xml_files ${xml_files} ${CMAKE_CURRENT_SOURCE_DIR}/actions-comm/actio foreach(x actions-comm actions-storage app-bittorrent app-chainsend app-masterworker app-pingpong app-token-ring async-yield async-wait async-waitall async-waitany cloud-capping cloud-masterworker cloud-migration cloud-simple cloud-two-tasks dht-chord dht-pastry dht-kademlia platform-failures io-file io-remote io-storage task-priority - process-create process-kill process-migration process-suspend platform-properties synchro-semaphore + process-create process-daemon process-kill process-migration process-suspend platform-properties synchro-semaphore process-startkilltime) ADD_TESH_FACTORIES(msg-${x} "thread;ucontext;raw;boost" --setenv bindir=${CMAKE_BINARY_DIR}/examples/msg/${x} --setenv srcdir=${CMAKE_HOME_DIRECTORY}/examples/platforms --cd ${CMAKE_HOME_DIRECTORY}/examples/msg/${x} ${x}.tesh) endforeach() diff --git a/examples/msg/process-daemon/process-daemon.c b/examples/msg/process-daemon/process-daemon.c new file mode 100644 index 0000000000..2806042ddd --- /dev/null +++ b/examples/msg/process-daemon/process-daemon.c @@ -0,0 +1,49 @@ +/* Copyright (c) 2017. The SimGrid Team. All rights reserved. */ + +/* This program is free software; you can redistribute it and/or modify it + * under the terms of the license (GNU LGPL) which comes with this package. */ + +#include "simgrid/msg.h" + +XBT_LOG_NEW_DEFAULT_CATEGORY(msg_process_daemon, "Messages specific for this msg example"); + +/* The worker process, working for a while before leaving */ +static int worker(int argc, char* argv[]) +{ + XBT_INFO("Let's do some work (for 10 sec on Boivin)."); + msg_task_t task = MSG_task_create("easy work", 980.95e6, 0, NULL); + MSG_task_execute(task); + MSG_task_destroy(task); + + XBT_INFO("I'm done now. I leave even if it makes the daemon die."); + return 0; +} + +/* The daemon, displaying a message every 3 seconds until all other processes stop */ +static int daemon(int argc, char* argv[]) +{ + MSG_process_daemonize(MSG_process_self()); + + while (1) { + XBT_INFO("Hello from the infinite loop"); + MSG_process_sleep(3.0); + } + + XBT_INFO("I will never reach that point: daemons are killed when regular processes are done"); + return 0; +} + +int main(int argc, char* argv[]) +{ + MSG_init(&argc, argv); + xbt_assert(argc > 1, "Usage: %s platform_file\n\tExample: %s msg_platform.xml\n", argv[0], argv[0]); + + MSG_create_environment(argv[1]); + xbt_dynar_t hosts = MSG_hosts_as_dynar(); + MSG_process_create("worker", worker, NULL, xbt_dynar_getfirst_as(hosts, msg_host_t)); + MSG_process_create("daemon", daemon, NULL, xbt_dynar_getlast_as(hosts, msg_host_t)); + xbt_dynar_free(&hosts); + msg_error_t res = MSG_main(); + + return res != MSG_OK; +} diff --git a/examples/msg/process-daemon/process-daemon.tesh b/examples/msg/process-daemon/process-daemon.tesh new file mode 100644 index 0000000000..25c0f10608 --- /dev/null +++ b/examples/msg/process-daemon/process-daemon.tesh @@ -0,0 +1,11 @@ +#! ./tesh + +p Testing the process daemonization feature of MSG + +$ $SG_TEST_EXENV ${bindir:=.}/process-daemon ${srcdir:=.}/small_platform.xml "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" +> [ 0.000000] (1:worker@Boivin) Let's do some work (for 10 sec on Boivin). +> [ 0.000000] (2:daemon@Tremblay) Hello from the infinite loop +> [ 3.000000] (2:daemon@Tremblay) Hello from the infinite loop +> [ 6.000000] (2:daemon@Tremblay) Hello from the infinite loop +> [ 9.000000] (2:daemon@Tremblay) Hello from the infinite loop +> [ 10.000000] (1:worker@Boivin) I'm done now. I leave even if it makes the daemon die. diff --git a/include/simgrid/msg.h b/include/simgrid/msg.h index c65b456a2c..c553e6e088 100644 --- a/include/simgrid/msg.h +++ b/include/simgrid/msg.h @@ -316,6 +316,7 @@ XBT_PUBLIC(int) MSG_process_is_suspended(msg_process_t process); XBT_PUBLIC(void) MSG_process_on_exit(int_f_pvoid_pvoid_t fun, void *data); XBT_PUBLIC(void) MSG_process_auto_restart_set(msg_process_t process, int auto_restart); +XBT_PUBLIC(void) MSG_process_daemonize(msg_process_t process); XBT_PUBLIC(msg_process_t) MSG_process_restart(msg_process_t process); /************************** Task handling ************************************/ diff --git a/src/msg/msg_process.cpp b/src/msg/msg_process.cpp index 72f92071b5..cf9b59da86 100644 --- a/src/msg/msg_process.cpp +++ b/src/msg/msg_process.cpp @@ -458,7 +458,7 @@ void MSG_process_on_exit(int_f_pvoid_pvoid_t fun, void *data) { XBT_PUBLIC(void) MSG_process_auto_restart_set(msg_process_t process, int auto_restart) { simcall_process_auto_restart_set(process,auto_restart); } -/* +/** * \ingroup m_process_management * \brief Restarts a process from the beginning. */ @@ -466,4 +466,14 @@ XBT_PUBLIC(msg_process_t) MSG_process_restart(msg_process_t process) { return simcall_process_restart(process); } +/** @ingroup m_process_management + * @brief This process will be terminated automatically when the last non-daemon process finishes + */ +XBT_PUBLIC(void) MSG_process_daemonize(msg_process_t process) +{ + simgrid::simix::kernelImmediate([process]() { + process->daemonize(); + }); +} + SG_END_DECL() diff --git a/src/simix/ActorImpl.cpp b/src/simix/ActorImpl.cpp index 970ececb15..502ffeaf12 100644 --- a/src/simix/ActorImpl.cpp +++ b/src/simix/ActorImpl.cpp @@ -168,6 +168,35 @@ ActorImpl::~ActorImpl() xbt_dict_free(&this->properties); } +static int dying_daemon(void* exit_status, void* data) +{ + std::vector* vect = &simix_global->daemons; + + auto it = std::find(vect->begin(), vect->end(), static_cast(data)); + xbt_assert(it != vect->end(), "The dying daemon is not a daemon after all. Please report that bug."); + + /* Don't move the whole content since we don't really care about the order */ + std::swap(*it, vect->back()); + vect->pop_back(); + + return 0; +} +/** This process will be terminated automatically when the last non-daemon process finishes */ +void ActorImpl::daemonize() +{ + if (!daemon) { + daemon = true; + simix_global->daemons.push_back(this); + SIMIX_process_on_exit(this, dying_daemon, this); + } +} + +/** Whether this process is daemonized */ +bool ActorImpl::isDaemon() +{ + return daemon; +} + void create_maestro(std::function code) { smx_actor_t maestro = nullptr; diff --git a/src/simix/ActorImpl.hpp b/src/simix/ActorImpl.hpp index c7ce8cd171..8bab69bc34 100644 --- a/src/simix/ActorImpl.hpp +++ b/src/simix/ActorImpl.hpp @@ -85,7 +85,11 @@ public: simgrid::s4u::ActorPtr iface() { return s4u::ActorPtr(&piface_); } + void daemonize(); + bool isDaemon(); + private: + bool daemon = false; std::atomic_int_fast32_t refcount_ { 1 }; simgrid::s4u::Actor piface_; // Our interface is part of ourselves }; diff --git a/src/simix/smx_global.cpp b/src/simix/smx_global.cpp index 184472573a..0c2a87f3f4 100644 --- a/src/simix/smx_global.cpp +++ b/src/simix/smx_global.cpp @@ -541,7 +541,15 @@ void SIMIX_run() /* Clean processes to destroy */ SIMIX_process_empty_trash(); - XBT_DEBUG("### time %f, empty %d", time, xbt_dynar_is_empty(simix_global->process_to_run)); + XBT_DEBUG("### time %f, #processes %zu, #to_run %zu", time, simix_global->process_list.size(), + xbt_dynar_length(simix_global->process_to_run)); + + /* If only daemon processes remain, cancel their actions, mark them to die and reschedule them */ + if (simix_global->process_list.size() == simix_global->daemons.size()) + for (const auto& dmon : simix_global->daemons) { + XBT_DEBUG("Kill %s", dmon->cname()); + SIMIX_process_kill(dmon, simix_global->maestro_process); + } if (xbt_dynar_is_empty(simix_global->process_to_run) && !simix_global->process_list.empty()) diff --git a/src/simix/smx_private.h b/src/simix/smx_private.h index f0072b96e0..6999488aab 100644 --- a/src/simix/smx_private.h +++ b/src/simix/smx_private.h @@ -49,6 +49,8 @@ public: std::vector> tasks; std::vector> tasksTemp; + + std::vector daemons; }; } -- 2.20.1