[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
Thu Aug 28 13:19:24 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/5] [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 e579f6012ce862..d90f930ddfe594 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 0f0564403c0e20..0d8a492b808f60 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/5] [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 d90f930ddfe594..ac8f4431657888 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 0d8a492b808f60..e486fb5cca9850 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"
 

>From 5089515506ac06fcc9e97dab76f8567c10c9d8ea Mon Sep 17 00:00:00 2001
From: David Parks <dparks at nvidia.com>
Date: Wed, 27 Aug 2025 14:01:03 -0700
Subject: [PATCH 3/5] [flang-rt] Cleanup dead code. 	modified:  
 ../../include/flang-rt/runtime/environment.h

---
 flang-rt/include/flang-rt/runtime/environment.h | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/flang-rt/include/flang-rt/runtime/environment.h b/flang-rt/include/flang-rt/runtime/environment.h
index ac8f4431657888..b12d6083a6c9a4 100644
--- a/flang-rt/include/flang-rt/runtime/environment.h
+++ b/flang-rt/include/flang-rt/runtime/environment.h
@@ -15,20 +15,6 @@
 
 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" {
-bool RTNAME(RegisterConfigureEnv)(void (*)(int, const char *[], const char *[],
-                                      const EnvironmentDefaultList *),
-    void (*)(
-        int, const char *[], const char *[], const EnvironmentDefaultList *));
-}
-#endif
-
 namespace Fortran::runtime {
 
 class Terminator;

>From 20c528a7f9a8eb2e96c9db031e53303aff984c90 Mon Sep 17 00:00:00 2001
From: David Parks <dparks at nvidia.com>
Date: Thu, 28 Aug 2025 05:45:02 -0700
Subject: [PATCH 4/5] [flang-rt] Run post environment configuration callback
 functions in the order they are registered. 	modified:   environment.cpp

---
 flang-rt/lib/runtime/environment.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flang-rt/lib/runtime/environment.cpp b/flang-rt/lib/runtime/environment.cpp
index e486fb5cca9850..6609e05520dfac 100644
--- a/flang-rt/lib/runtime/environment.cpp
+++ b/flang-rt/lib/runtime/environment.cpp
@@ -186,7 +186,7 @@ void ExecutionEnvironment::Configure(int ac, const char *av[],
   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) {
+    for (auto i = 0; i != nPostConfigEnvCallback; ++i) {
       PostConfigEnvCallback[i](ac, av, env, envDefaults);
     }
   }

>From 7bb8ab747e58acc58605fa0564b70f405b02b814 Mon Sep 17 00:00:00 2001
From: David Parks <dparks at nvidia.com>
Date: Thu, 28 Aug 2025 13:18:55 -0700
Subject: [PATCH 5/5] [flang-rt] Incorporate latest review comments. 
 modified:   ../../include/flang-rt/runtime/environment.h 	modified:  
 environment.cpp

---
 .../include/flang-rt/runtime/environment.h    | 15 ++-------
 flang-rt/lib/runtime/environment.cpp          | 33 ++++++++++++-------
 2 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/flang-rt/include/flang-rt/runtime/environment.h b/flang-rt/include/flang-rt/runtime/environment.h
index b12d6083a6c9a4..e7b1f2cc9d4a45 100644
--- a/flang-rt/include/flang-rt/runtime/environment.h
+++ b/flang-rt/include/flang-rt/runtime/environment.h
@@ -48,20 +48,9 @@ struct 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.
-  // 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.
-
+  // Maximum number of registered pre and post ExecutionEnvironment::Configure()
+  // callback 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);
diff --git a/flang-rt/lib/runtime/environment.cpp b/flang-rt/lib/runtime/environment.cpp
index 6609e05520dfac..771c161bbfce78 100644
--- a/flang-rt/lib/runtime/environment.cpp
+++ b/flang-rt/lib/runtime/environment.cpp
@@ -29,6 +29,22 @@ RT_VAR_ATTRS ExecutionEnvironment executionEnvironment;
 RT_OFFLOAD_VAR_GROUP_END
 #endif // FLANG_RUNTIME_NO_GLOBAL_VAR_DEFS
 
+// Optional callback routines to be invoked pre and post execution
+// environment setup.
+// 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 int nPreConfigEnvCallback{0};
+static void (*PreConfigEnvCallback[ExecutionEnvironment::nConfigEnvCallback])(
+    int, const char *[], const char *[], const EnvironmentDefaultList *){
+    nullptr};
+
+static int nPostConfigEnvCallback{0};
+static void (*PostConfigEnvCallback[ExecutionEnvironment::nConfigEnvCallback])(
+    int, const char *[], const char *[], const EnvironmentDefaultList *){
+    nullptr};
+
 static void SetEnvironmentDefaults(const EnvironmentDefaultList *envDefaults) {
   if (!envDefaults) {
     return;
@@ -82,7 +98,7 @@ void ExecutionEnvironment::Configure(int ac, const char *av[],
   if (0 != nPreConfigEnvCallback) {
     // Run an optional callback function after the core of the
     // ExecutionEnvironment() logic.
-    for (auto i = 0; i != nPreConfigEnvCallback; ++i) {
+    for (int i{0}; i != nPostConfigEnvCallback; ++i) {
       PreConfigEnvCallback[i](ac, av, env, envDefaults);
     }
   }
@@ -186,7 +202,7 @@ void ExecutionEnvironment::Configure(int ac, const char *av[],
   if (0 != nPostConfigEnvCallback) {
     // Run an optional callback function in reverse order of registration
     // after the core of the ExecutionEnvironment() logic.
-    for (auto i = 0; i != nPostConfigEnvCallback; ++i) {
+    for (int i{0}; i != nPostConfigEnvCallback; ++i) {
       PostConfigEnvCallback[i](ac, av, env, envDefaults);
     }
   }
@@ -279,21 +295,16 @@ bool RTNAME(RegisterConfigureEnv)(
   bool ret{true};
 
   if (nullptr != pre) {
-    if (executionEnvironment.nPreConfigEnvCallback <
-        executionEnvironment.nConfigEnvCallback) {
-      executionEnvironment
-          .PreConfigEnvCallback[executionEnvironment.nPreConfigEnvCallback++] =
-          pre;
+    if (nPreConfigEnvCallback < ExecutionEnvironment::nConfigEnvCallback) {
+      PreConfigEnvCallback[nPreConfigEnvCallback++] = pre;
     } else {
       ret = false;
     }
   }
 
   if (ret && nullptr != post) {
-    if (executionEnvironment.nPostConfigEnvCallback <
-        executionEnvironment.nConfigEnvCallback) {
-      executionEnvironment.PostConfigEnvCallback[executionEnvironment
-              .nPostConfigEnvCallback++] = post;
+    if (nPostConfigEnvCallback < ExecutionEnvironment::nConfigEnvCallback) {
+      PostConfigEnvCallback[nPostConfigEnvCallback++] = post;
     } else {
       ret = false;
     }



More information about the llvm-commits mailing list