[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