From e8eec0183feb1a1e5f42f3cd668bdf0f657fd228 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Tue, 28 May 2024 01:27:50 +0200
Subject: [PATCH] Add a simple stop() function to the language

This allows to decide some actions in the script when a stoppage is
manually required.

By now it just checks that the presence of a recent "STOP" file in the
execution directory. A simple use is for instance:
```
  if (stop()) {
    checkpoint_and_exit();
  }
```
---
 src/language/modules/CoreModule.cpp | 28 ++++++++++++++++++++++++++++
 src/utils/ExecutionStatManager.cpp  |  6 ++++++
 src/utils/ExecutionStatManager.hpp  |  2 ++
 3 files changed, 36 insertions(+)

diff --git a/src/language/modules/CoreModule.cpp b/src/language/modules/CoreModule.cpp
index d031a75bc..b73f7f0a2 100644
--- a/src/language/modules/CoreModule.cpp
+++ b/src/language/modules/CoreModule.cpp
@@ -31,6 +31,7 @@
 #include <language/utils/UnaryOperatorRegisterForRn.hpp>
 #include <language/utils/UnaryOperatorRegisterForRnxn.hpp>
 #include <language/utils/UnaryOperatorRegisterForZ.hpp>
+#include <utils/ExecutionStatManager.hpp>
 #include <utils/Messenger.hpp>
 #include <utils/PugsUtils.hpp>
 #include <utils/RandomEngine.hpp>
@@ -144,6 +145,33 @@ CoreModule::CoreModule() : BuiltinModule(true)
 
                                                      ));
 
+  this->_addBuiltinFunction("stop",
+                            std::function(
+
+                              []() -> bool {
+                                bool has_stop_file = false;
+
+                                if (parallel::rank() == 0) {
+                                  std::filesystem::path stop_file("STOP");
+                                  if (std::filesystem::exists(stop_file)) {
+                                    const double elapse_time = ExecutionStatManager::getInstance().getElapseTime();
+
+                                    const double stop_file_age = std::chrono::duration_cast<std::chrono::seconds>(
+                                                                   std::chrono::system_clock::now() -
+                                                                   std::chrono::clock_cast<std::chrono::system_clock>(
+                                                                     std::filesystem::last_write_time(stop_file)))
+                                                                   .count();
+
+                                    has_stop_file = elapse_time > stop_file_age;
+                                  }
+                                }
+                                parallel::broadcast(has_stop_file, 0);
+
+                                return has_stop_file;
+                              }
+
+                              ));
+
   this->_addNameValue("cout", ast_node_data_type_from<std::shared_ptr<const OStream>>,
                       EmbeddedData{std::make_shared<DataHandler<const OStream>>(std::make_shared<OStream>(std::cout))});
 
diff --git a/src/utils/ExecutionStatManager.cpp b/src/utils/ExecutionStatManager.cpp
index d24d821b4..06f7942cf 100644
--- a/src/utils/ExecutionStatManager.cpp
+++ b/src/utils/ExecutionStatManager.cpp
@@ -161,6 +161,12 @@ ExecutionStatManager::printInfo()
   }
 }
 
+double
+ExecutionStatManager::getElapseTime() const
+{
+  return m_elapse_time.seconds();
+}
+
 double
 ExecutionStatManager::getCumulativeElapseTime() const
 {
diff --git a/src/utils/ExecutionStatManager.hpp b/src/utils/ExecutionStatManager.hpp
index 75adce89b..f07099eec 100644
--- a/src/utils/ExecutionStatManager.hpp
+++ b/src/utils/ExecutionStatManager.hpp
@@ -29,6 +29,8 @@ class ExecutionStatManager
   ~ExecutionStatManager()                           = default;
 
  public:
+  double getElapseTime() const;
+
   double getCumulativeElapseTime() const;
 
   double getCumulativeTotalCPUTime() const;
-- 
GitLab