Environment Variable Guidelines
WORK IN PROGRESS
The following material is a work in progress and should not be considered complete or ready for public use.
The runtime is affected by certain environment variables. This guide attempts to set out the conditions under which you should create environment variables to control certain runtime behaviour, and what to call them.
In general environment variables exist in a single namespace visible to a process as a whole. Given the single namespace environment variables are best used to present process-wide global values that affect the entire process. One example of a process-wide global value would be the default thread stack size if no other API is used to adjust the thread stack size.
If there is a process-wide global value that impacts the runtime behaviour and it would be useful to change without recompiling the application then this may be a candidate for exposing through an environment variable.
If there is a per-thread, per-lock, per-critical-section, or other finer grained value that impacts the runtime behaviour, then it is not likely a good candidate to expose via an environment variable. The problem with using an environment variable to change the behaviour of a thread is that the thread identifier is not known until runtime and thus one is unable to easily express to which thread the environment variables applies. It is still possible to associate a set of global defaults with a context, but it would require a more complex framework.
If the environment variable might change over the course of the process execution and that changed value needs reloading then this is not a good use of an environment variable. An environment variable will be read once at startup with the processed value stored once into the global variable that tracks the value.
How do we translate environment variables into runtime tuning values?
- Processed by an extra library
- Define an API for manipulating the behaviour.
- Create a shared library that calls the API functions if an environment variable is set.
- Set the environment variable and preload the library.
Processing with an extra library has the disbenefit of not working with static linking. To work with static linking you would need a static version that adds an initializer, but initializer order is difficult to get correct, resulting in ordering issues for setting the default.
- Processed by ld.so
- The rtld startup already walks all of the env vars looking for it's own env vars.
- Add hooks to env var walk for other parts of the library.
- Other parts of the library register hooks at built time which allow them to set globals based on env vars.
- Library code takes appropriate action given global values.
Adding more to the rtld o(n^2) env var walk would not have any serious performance impact on startup. The hooks isolate the env var processing for security review.
- Processed at time of use
- Env var loaded at time of use and parsed.
- Global is set based on env var value.
- Code is present on all use paths but elided once env var is set.
This means that all functions that are affected by the environment variable would have to check for an uninitialized value, initialize as required, and then use it. This may be problematic with threads present and has performance implications.