[llvm] [flang-rt] Add the ability to have user supplied callback functions to further customize the runtime environment. (PR #155646)

David Parks via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 27 13:59:02 PDT 2025


https://github.com/d-parks updated https://github.com/llvm/llvm-project/pull/155646

>From b616c34fe3bc0a8992ffc7dc8eb993b5ed76538c Mon Sep 17 00:00:00 2001
From: David Parks <dparks at nvidia.com>
Date: Wed, 27 Aug 2025 08:22:09 -0700
Subject: [PATCH 1/2] [flang-rt] Add the ability to have user supplied callback
 functions to further customize the runtime environment.

	modified:   flang-rt/include/flang-rt/runtime/environment.h
	modified:   flang-rt/lib/runtime/environment.cpp
---
 .../include/flang-rt/runtime/environment.h    | 21 +++++++++++++
 flang-rt/lib/runtime/environment.cpp          | 31 +++++++++++++++++++
 2 files changed, 52 insertions(+)

diff --git a/flang-rt/include/flang-rt/runtime/environment.h b/flang-rt/include/flang-rt/runtime/environment.h
index e579f6012ce86..d90f930ddfe59 100644
--- a/flang-rt/include/flang-rt/runtime/environment.h
+++ b/flang-rt/include/flang-rt/runtime/environment.h
@@ -11,9 +11,22 @@
 
 #include "flang/Common/optional.h"
 #include "flang/Decimal/decimal.h"
+#include "flang/Runtime/entry-names.h"
 
 struct EnvironmentDefaultList;
 
+// ExecutionEnvironment::Configure() allows for optional callback functions
+// to be run pre and post the core logic.
+// Most likely scenario is when a user supplied constructor function is
+// run prior to _QQmain calling RTNAME(ProgramStart)().
+
+extern "C" {
+void RTNAME(RegisterConfigureEnv)(void (*)(int, const char *[], const char *[],
+                                      const EnvironmentDefaultList *),
+    void (*)(
+        int, const char *[], const char *[], const EnvironmentDefaultList *));
+}
+
 namespace Fortran::runtime {
 
 class Terminator;
@@ -42,6 +55,14 @@ struct ExecutionEnvironment {
       ExecutionEnvironment(){};
   void Configure(int argc, const char *argv[], const char *envp[],
       const EnvironmentDefaultList *envDefaults);
+
+  // Optional callback routines to be invoked pre and post
+  // execution environment setup.
+  void (*PreConfigureEnv)(int, const char *[], const char *[],
+      const EnvironmentDefaultList *){nullptr};
+  void (*PostConfigureEnv)(int, const char *[], const char *[],
+      const EnvironmentDefaultList *){nullptr};
+
   const char *GetEnv(
       const char *name, std::size_t name_length, const Terminator &terminator);
 
diff --git a/flang-rt/lib/runtime/environment.cpp b/flang-rt/lib/runtime/environment.cpp
index 0f0564403c0e2..0d8a492b808f6 100644
--- a/flang-rt/lib/runtime/environment.cpp
+++ b/flang-rt/lib/runtime/environment.cpp
@@ -78,6 +78,13 @@ void ExecutionEnvironment::Configure(int ac, const char *av[],
   argc = ac;
   argv = av;
   SetEnvironmentDefaults(envDefaults);
+
+  if (PreConfigureEnv) {
+    // Run an optional callback function prior to the core of the
+    // ExecutionEnvironment() logic.
+    PreConfigureEnv(ac, av, env, envDefaults);
+  }
+
 #ifdef _WIN32
   envp = _environ;
 #else
@@ -173,6 +180,12 @@ void ExecutionEnvironment::Configure(int ac, const char *av[],
   }
 
   // TODO: Set RP/ROUND='PROCESSOR_DEFINED' from environment
+
+  if (PostConfigureEnv) {
+    // Run an optional callback function after the core of the
+    // ExecutionEnvironment() logic.
+    PostConfigureEnv(ac, av, env, envDefaults);
+  }
 }
 
 const char *ExecutionEnvironment::GetEnv(
@@ -249,4 +262,22 @@ std::int32_t ExecutionEnvironment::UnsetEnv(
   return status;
 }
 
+extern "C" {
+
+// User supplied callback functions to further customize the configuration
+// of the runtime environment.
+// The pre and post callback functions are called upon entry and exit
+// of ExecutionEnvironment::Configure() respectively.
+
+void RTNAME(RegisterConfigureEnv)(
+    void (*pre)(int argc, const char *argv[], const char *envp[],
+        const EnvironmentDefaultList *),
+    void (*post)(int argc, const char *argv[], const char *envp[],
+        const EnvironmentDefaultList *)) {
+
+  executionEnvironment.PreConfigureEnv = pre;
+  executionEnvironment.PostConfigureEnv = post;
+}
+} // extern "C"
+
 } // namespace Fortran::runtime

>From 3285393617a100bc52c464fbae023813b75cf7dd Mon Sep 17 00:00:00 2001
From: David Parks <dparks at nvidia.com>
Date: Wed, 27 Aug 2025 13:57:31 -0700
Subject: [PATCH 2/2] [flang-rt] Incorporate review comment #155646. 
 modified:   ../../include/flang-rt/runtime/environment.h 	modified:  
 environment.cpp

---
 .../include/flang-rt/runtime/environment.h    | 35 ++++++++++---
 flang-rt/lib/runtime/environment.cpp          | 51 ++++++++++++++-----
 2 files changed, 66 insertions(+), 20 deletions(-)

diff --git a/flang-rt/include/flang-rt/runtime/environment.h b/flang-rt/include/flang-rt/runtime/environment.h
index d90f930ddfe59..ac8f443165788 100644
--- a/flang-rt/include/flang-rt/runtime/environment.h
+++ b/flang-rt/include/flang-rt/runtime/environment.h
@@ -15,17 +15,19 @@
 
 struct EnvironmentDefaultList;
 
+#if 0
 // ExecutionEnvironment::Configure() allows for optional callback functions
 // to be run pre and post the core logic.
 // Most likely scenario is when a user supplied constructor function is
 // run prior to _QQmain calling RTNAME(ProgramStart)().
 
 extern "C" {
-void RTNAME(RegisterConfigureEnv)(void (*)(int, const char *[], const char *[],
+bool RTNAME(RegisterConfigureEnv)(void (*)(int, const char *[], const char *[],
                                       const EnvironmentDefaultList *),
     void (*)(
         int, const char *[], const char *[], const EnvironmentDefaultList *));
 }
+#endif
 
 namespace Fortran::runtime {
 
@@ -48,6 +50,10 @@ RT_API_ATTRS Fortran::common::optional<Convert> GetConvertFromString(
     const char *, std::size_t);
 
 struct ExecutionEnvironment {
+
+  typedef void (*ConfigEnvCallbackPtr)(
+      int, const char *[], const char *[], const EnvironmentDefaultList *);
+
 #if !defined(_OPENMP)
   // FIXME: https://github.com/llvm/llvm-project/issues/84942
   constexpr
@@ -58,10 +64,18 @@ struct ExecutionEnvironment {
 
   // Optional callback routines to be invoked pre and post
   // execution environment setup.
-  void (*PreConfigureEnv)(int, const char *[], const char *[],
-      const EnvironmentDefaultList *){nullptr};
-  void (*PostConfigureEnv)(int, const char *[], const char *[],
-      const EnvironmentDefaultList *){nullptr};
+  // RTNAME(RegisterConfigureEnv) will return true if callback
+  // function(s) is(are) successfully added to small array of
+  // pointers.  False if more than nConfigEnvCallback registrations
+  // for either pre or post functions.
+
+  static constexpr int nConfigEnvCallback{8};
+  int nPreConfigEnvCallback{0};
+  void (*PreConfigEnvCallback[nConfigEnvCallback])(int, const char *[],
+      const char *[], const EnvironmentDefaultList *){nullptr};
+  int nPostConfigEnvCallback{0};
+  void (*PostConfigEnvCallback[nConfigEnvCallback])(int, const char *[],
+      const char *[], const EnvironmentDefaultList *){nullptr};
 
   const char *GetEnv(
       const char *name, std::size_t name_length, const Terminator &terminator);
@@ -97,6 +111,15 @@ RT_OFFLOAD_VAR_GROUP_BEGIN
 extern RT_VAR_ATTRS ExecutionEnvironment executionEnvironment;
 RT_OFFLOAD_VAR_GROUP_END
 
-} // namespace Fortran::runtime
+// ExecutionEnvironment::Configure() allows for optional callback functions
+// to be run pre and post the core logic.
+// Most likely scenario is when a user supplied constructor function is
+// run prior to _QQmain calling RTNAME(ProgramStart)().
+
+extern "C" {
+bool RTNAME(RegisterConfigureEnv)(ExecutionEnvironment::ConfigEnvCallbackPtr,
+    ExecutionEnvironment::ConfigEnvCallbackPtr);
+}
 
+} // namespace Fortran::runtime
 #endif // FLANG_RT_RUNTIME_ENVIRONMENT_H_
diff --git a/flang-rt/lib/runtime/environment.cpp b/flang-rt/lib/runtime/environment.cpp
index 0d8a492b808f6..e486fb5cca985 100644
--- a/flang-rt/lib/runtime/environment.cpp
+++ b/flang-rt/lib/runtime/environment.cpp
@@ -79,10 +79,12 @@ void ExecutionEnvironment::Configure(int ac, const char *av[],
   argv = av;
   SetEnvironmentDefaults(envDefaults);
 
-  if (PreConfigureEnv) {
-    // Run an optional callback function prior to the core of the
+  if (0 != nPreConfigEnvCallback) {
+    // Run an optional callback function after the core of the
     // ExecutionEnvironment() logic.
-    PreConfigureEnv(ac, av, env, envDefaults);
+    for (auto i = 0; i != nPreConfigEnvCallback; ++i) {
+      PreConfigEnvCallback[i](ac, av, env, envDefaults);
+    }
   }
 
 #ifdef _WIN32
@@ -181,10 +183,12 @@ void ExecutionEnvironment::Configure(int ac, const char *av[],
 
   // TODO: Set RP/ROUND='PROCESSOR_DEFINED' from environment
 
-  if (PostConfigureEnv) {
-    // Run an optional callback function after the core of the
-    // ExecutionEnvironment() logic.
-    PostConfigureEnv(ac, av, env, envDefaults);
+  if (0 != nPostConfigEnvCallback) {
+    // Run an optional callback function in reverse order of registration
+    // after the core of the ExecutionEnvironment() logic.
+    for (auto i = nPostConfigEnvCallback - 1; i >= 0; --i) {
+      PostConfigEnvCallback[i](ac, av, env, envDefaults);
+    }
   }
 }
 
@@ -269,14 +273,33 @@ extern "C" {
 // The pre and post callback functions are called upon entry and exit
 // of ExecutionEnvironment::Configure() respectively.
 
-void RTNAME(RegisterConfigureEnv)(
-    void (*pre)(int argc, const char *argv[], const char *envp[],
-        const EnvironmentDefaultList *),
-    void (*post)(int argc, const char *argv[], const char *envp[],
-        const EnvironmentDefaultList *)) {
+bool RTNAME(RegisterConfigureEnv)(
+    ExecutionEnvironment::ConfigEnvCallbackPtr pre,
+    ExecutionEnvironment::ConfigEnvCallbackPtr post) {
+  bool ret{true};
+
+  if (nullptr != pre) {
+    if (executionEnvironment.nPreConfigEnvCallback <
+        executionEnvironment.nConfigEnvCallback) {
+      executionEnvironment
+          .PreConfigEnvCallback[executionEnvironment.nPreConfigEnvCallback++] =
+          pre;
+    } else {
+      ret = false;
+    }
+  }
+
+  if (ret && nullptr != post) {
+    if (executionEnvironment.nPostConfigEnvCallback <
+        executionEnvironment.nConfigEnvCallback) {
+      executionEnvironment.PostConfigEnvCallback[executionEnvironment
+              .nPostConfigEnvCallback++] = post;
+    } else {
+      ret = false;
+    }
+  }
 
-  executionEnvironment.PreConfigureEnv = pre;
-  executionEnvironment.PostConfigureEnv = post;
+  return ret;
 }
 } // extern "C"
 



More information about the llvm-commits mailing list