Skip to content

Commit f9cac5f

Browse files
d-parksDavid Parks
andauthored
[flang-rt] Add the ability to have user supplied callback functions to further customize the runtime environment. (#155646)
Add the ability to have pre and post call back functions to ExecutionEnvironment::Configure() to allow further customization of the flang runtime environment (called from _FortranAStartProgam) in situations where either the desired features/functionality are proprietary or are too specific to be accepted by the flang community. Example: Custom constructor object linked with flang objects: ``` #include "flang-rt/runtime/environment.h" #include "flang/Runtime/entry-names.h" #include "flang/Runtime/extensions.h" namespace Fortran::runtime { // Do something specific to the flang runtime environment prior to the // core logic of ExecutionEnvironment::Configure(). static void CustomPreConfigureEnv(int argc, const char *argv[], const char *envp[], const EnvironmentDefaultList *envDefaultList) { puts(__func__); } // Do something specific to the flang runtime environment after running the // core logic of ExecutionEnvironment::Configure(). static void CustomPostConfigureEnv(int argc, const char *argv[], const char *envp[], const EnvironmentDefaultList *envDefaultList) { puts(__func__); } void __attribute__((constructor)) CustomInitCstor(void) { // Possibilities: // RTNAME(RegisterConfigureEnv)(&CustomPreConfigureEnv, // &CustomPostConfigureEnv); RTNAME(RegisterConfigureEnv)(nullptr, // &CustomPostConfigureEnv); RTNAME(RegisterConfigureEnv)(&CustomPreConfigureEnv, nullptr); } } // namespace Fortran::runtime ``` --------- Co-authored-by: David Parks <[email protected]>
1 parent 5c9b497 commit f9cac5f

File tree

2 files changed

+85
-1
lines changed

2 files changed

+85
-1
lines changed

flang-rt/include/flang-rt/runtime/environment.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "flang/Common/optional.h"
1313
#include "flang/Decimal/decimal.h"
14+
#include "flang/Runtime/entry-names.h"
1415

1516
struct EnvironmentDefaultList;
1617

@@ -35,13 +36,22 @@ RT_API_ATTRS common::optional<Convert> GetConvertFromString(
3536
const char *, std::size_t);
3637

3738
struct ExecutionEnvironment {
39+
40+
typedef void (*ConfigEnvCallbackPtr)(
41+
int, const char *[], const char *[], const EnvironmentDefaultList *);
42+
3843
#if !defined(_OPENMP)
3944
// FIXME: https://github.com/llvm/llvm-project/issues/84942
4045
constexpr
4146
#endif
4247
ExecutionEnvironment(){};
4348
void Configure(int argc, const char *argv[], const char *envp[],
4449
const EnvironmentDefaultList *envDefaults);
50+
51+
// Maximum number of registered pre and post ExecutionEnvironment::Configure()
52+
// callback functions.
53+
static constexpr int nConfigEnvCallback{8};
54+
4555
const char *GetEnv(
4656
const char *name, std::size_t name_length, const Terminator &terminator);
4757

@@ -76,6 +86,15 @@ RT_OFFLOAD_VAR_GROUP_BEGIN
7686
extern RT_VAR_ATTRS ExecutionEnvironment executionEnvironment;
7787
RT_OFFLOAD_VAR_GROUP_END
7888

79-
} // namespace Fortran::runtime
89+
// ExecutionEnvironment::Configure() allows for optional callback functions
90+
// to be run pre and post the core logic.
91+
// Most likely scenario is when a user supplied constructor function is
92+
// run prior to _QQmain calling RTNAME(ProgramStart)().
93+
94+
extern "C" {
95+
bool RTNAME(RegisterConfigureEnv)(ExecutionEnvironment::ConfigEnvCallbackPtr,
96+
ExecutionEnvironment::ConfigEnvCallbackPtr);
97+
}
8098

99+
} // namespace Fortran::runtime
81100
#endif // FLANG_RT_RUNTIME_ENVIRONMENT_H_

flang-rt/lib/runtime/environment.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ RT_VAR_ATTRS ExecutionEnvironment executionEnvironment;
2929
RT_OFFLOAD_VAR_GROUP_END
3030
#endif // FLANG_RUNTIME_NO_GLOBAL_VAR_DEFS
3131

32+
// Optional callback routines to be invoked pre and post execution
33+
// environment setup.
34+
// RTNAME(RegisterConfigureEnv) will return true if callback function(s)
35+
// is(are) successfully added to small array of pointers. False if more
36+
// than nConfigEnvCallback registrations for either pre or post functions.
37+
38+
static int nPreConfigEnvCallback{0};
39+
static void (*PreConfigEnvCallback[ExecutionEnvironment::nConfigEnvCallback])(
40+
int, const char *[], const char *[], const EnvironmentDefaultList *){
41+
nullptr};
42+
43+
static int nPostConfigEnvCallback{0};
44+
static void (*PostConfigEnvCallback[ExecutionEnvironment::nConfigEnvCallback])(
45+
int, const char *[], const char *[], const EnvironmentDefaultList *){
46+
nullptr};
47+
3248
static void SetEnvironmentDefaults(const EnvironmentDefaultList *envDefaults) {
3349
if (!envDefaults) {
3450
return;
@@ -77,6 +93,15 @@ void ExecutionEnvironment::Configure(int ac, const char *av[],
7793
argc = ac;
7894
argv = av;
7995
SetEnvironmentDefaults(envDefaults);
96+
97+
if (0 != nPreConfigEnvCallback) {
98+
// Run an optional callback function after the core of the
99+
// ExecutionEnvironment() logic.
100+
for (int i{0}; i != nPreConfigEnvCallback; ++i) {
101+
PreConfigEnvCallback[i](ac, av, env, envDefaults);
102+
}
103+
}
104+
80105
#ifdef _WIN32
81106
envp = _environ;
82107
#else
@@ -172,6 +197,14 @@ void ExecutionEnvironment::Configure(int ac, const char *av[],
172197
}
173198

174199
// TODO: Set RP/ROUND='PROCESSOR_DEFINED' from environment
200+
201+
if (0 != nPostConfigEnvCallback) {
202+
// Run an optional callback function in reverse order of registration
203+
// after the core of the ExecutionEnvironment() logic.
204+
for (int i{0}; i != nPostConfigEnvCallback; ++i) {
205+
PostConfigEnvCallback[i](ac, av, env, envDefaults);
206+
}
207+
}
175208
}
176209

177210
const char *ExecutionEnvironment::GetEnv(
@@ -248,4 +281,36 @@ std::int32_t ExecutionEnvironment::UnsetEnv(
248281
return status;
249282
}
250283

284+
extern "C" {
285+
286+
// User supplied callback functions to further customize the configuration
287+
// of the runtime environment.
288+
// The pre and post callback functions are called upon entry and exit
289+
// of ExecutionEnvironment::Configure() respectively.
290+
291+
bool RTNAME(RegisterConfigureEnv)(
292+
ExecutionEnvironment::ConfigEnvCallbackPtr pre,
293+
ExecutionEnvironment::ConfigEnvCallbackPtr post) {
294+
bool ret{true};
295+
296+
if (nullptr != pre) {
297+
if (nPreConfigEnvCallback < ExecutionEnvironment::nConfigEnvCallback) {
298+
PreConfigEnvCallback[nPreConfigEnvCallback++] = pre;
299+
} else {
300+
ret = false;
301+
}
302+
}
303+
304+
if (ret && nullptr != post) {
305+
if (nPostConfigEnvCallback < ExecutionEnvironment::nConfigEnvCallback) {
306+
PostConfigEnvCallback[nPostConfigEnvCallback++] = post;
307+
} else {
308+
ret = false;
309+
}
310+
}
311+
312+
return ret;
313+
}
314+
} // extern "C"
315+
251316
} // namespace Fortran::runtime

0 commit comments

Comments
 (0)