mirror of
https://github.com/intel/llvm.git
synced 2026-01-24 08:30:34 +08:00
[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 <dparks@nvidia.com>
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "flang/Common/optional.h"
|
||||
#include "flang/Decimal/decimal.h"
|
||||
#include "flang/Runtime/entry-names.h"
|
||||
|
||||
struct EnvironmentDefaultList;
|
||||
|
||||
@@ -35,6 +36,10 @@ RT_API_ATTRS 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
|
||||
@@ -42,6 +47,11 @@ struct ExecutionEnvironment {
|
||||
ExecutionEnvironment(){};
|
||||
void Configure(int argc, const char *argv[], const char *envp[],
|
||||
const EnvironmentDefaultList *envDefaults);
|
||||
|
||||
// Maximum number of registered pre and post ExecutionEnvironment::Configure()
|
||||
// callback functions.
|
||||
static constexpr int nConfigEnvCallback{8};
|
||||
|
||||
const char *GetEnv(
|
||||
const char *name, std::size_t name_length, const Terminator &terminator);
|
||||
|
||||
@@ -76,6 +86,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_
|
||||
|
||||
@@ -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;
|
||||
@@ -77,6 +93,15 @@ void ExecutionEnvironment::Configure(int ac, const char *av[],
|
||||
argc = ac;
|
||||
argv = av;
|
||||
SetEnvironmentDefaults(envDefaults);
|
||||
|
||||
if (0 != nPreConfigEnvCallback) {
|
||||
// Run an optional callback function after the core of the
|
||||
// ExecutionEnvironment() logic.
|
||||
for (int i{0}; i != nPreConfigEnvCallback; ++i) {
|
||||
PreConfigEnvCallback[i](ac, av, env, envDefaults);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
envp = _environ;
|
||||
#else
|
||||
@@ -172,6 +197,14 @@ void ExecutionEnvironment::Configure(int ac, const char *av[],
|
||||
}
|
||||
|
||||
// TODO: Set RP/ROUND='PROCESSOR_DEFINED' from environment
|
||||
|
||||
if (0 != nPostConfigEnvCallback) {
|
||||
// Run an optional callback function in reverse order of registration
|
||||
// after the core of the ExecutionEnvironment() logic.
|
||||
for (int i{0}; i != nPostConfigEnvCallback; ++i) {
|
||||
PostConfigEnvCallback[i](ac, av, env, envDefaults);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *ExecutionEnvironment::GetEnv(
|
||||
@@ -248,4 +281,36 @@ 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.
|
||||
|
||||
bool RTNAME(RegisterConfigureEnv)(
|
||||
ExecutionEnvironment::ConfigEnvCallbackPtr pre,
|
||||
ExecutionEnvironment::ConfigEnvCallbackPtr post) {
|
||||
bool ret{true};
|
||||
|
||||
if (nullptr != pre) {
|
||||
if (nPreConfigEnvCallback < ExecutionEnvironment::nConfigEnvCallback) {
|
||||
PreConfigEnvCallback[nPreConfigEnvCallback++] = pre;
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret && nullptr != post) {
|
||||
if (nPostConfigEnvCallback < ExecutionEnvironment::nConfigEnvCallback) {
|
||||
PostConfigEnvCallback[nPostConfigEnvCallback++] = post;
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
} // namespace Fortran::runtime
|
||||
|
||||
Reference in New Issue
Block a user