[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