Files
swift-mirror/stdlib/public/runtime/EnvironmentVariables.cpp
T
Mike Ash f7745f2094 [Runtime] Group environment variable types into a types namespace.
Rather than attempt to use standard C++ type names, create a namespace specifically for environment variable types and require vars to use a type from that namespace. This avoids the annoying collision between this `string` and `std::string`, and makes everything a bit more consistent. Rename the types a bit to be more appropriate for this context: boolean, uint8, and uint32, instead of bool, uint8_t, and uint32_t.
2026-05-14 15:16:17 -04:00

323 lines
11 KiB
C++

//===--- EnvironmentVariables.h - Debug variables. --------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Debug behavior conditionally enabled using environment variables.
//
//===----------------------------------------------------------------------===//
#include "swift/Runtime/Debug.h"
#include "swift/Runtime/Paths.h"
#include "swift/Runtime/EnvironmentVariables.h"
#include <string.h>
#include <inttypes.h>
#if defined(__ANDROID__)
#include <sys/system_properties.h>
#endif
using namespace swift;
namespace {
// Require all environment variable names to start with SWIFT_
static constexpr bool hasSwiftPrefix(const char *str) {
const char prefix[] = "SWIFT_";
for (unsigned i = 0; i < sizeof(prefix) - 1; i++)
if (str[i] != prefix[i])
return false;
return true;
}
#define VARIABLE(name, type, defaultValue, help) \
static_assert(hasSwiftPrefix(#name), "Names must start with SWIFT");
#include "EnvironmentVariables.def"
#if SWIFT_STDLIB_HAS_ENVIRON
// Value parsers. Add new functions named parse_<type> to accommodate more
// debug variable types.
static bool parse_boolean(const char *name, const char *value,
bool defaultValue) {
if (!value)
return defaultValue;
switch (value[0]) {
case 'Y':
case 'y':
case 'T':
case 't':
case '1':
return true;
case 'N':
case 'n':
case 'F':
case 'f':
case '0':
return false;
default:
swift::warning(RuntimeErrorFlagNone,
"Warning: cannot parse value %s=%s, defaulting to %s.\n",
name, value, defaultValue ? "true" : "false");
return defaultValue;
}
}
static uint8_t parse_uint8(const char *name, const char *value,
uint8_t defaultValue) {
if (!value)
return defaultValue;
char *end;
long n = strtol(value, &end, 0);
if (*end != '\0') {
swift::warning(RuntimeErrorFlagNone,
"Warning: cannot parse value %s=%s, defaulting to %u.\n",
name, value, defaultValue);
return defaultValue;
}
if (n < 0) {
swift::warning(RuntimeErrorFlagNone,
"Warning: %s=%s out of bounds, clamping to 0.\n",
name, value);
return 0;
}
if (n > UINT8_MAX) {
swift::warning(RuntimeErrorFlagNone,
"Warning: %s=%s out of bounds, clamping to %d.\n",
name, value, UINT8_MAX);
return UINT8_MAX;
}
return n;
}
static uint32_t parse_uint32(const char *name, const char *value,
uint32_t defaultValue) {
if (!value)
return defaultValue;
char *end;
long long n = strtoll(value, &end, 0);
if (*end != '\0') {
swift::warning(RuntimeErrorFlagNone,
"Warning: cannot parse value %s=%s, defaulting to %u.\n",
name, value, defaultValue);
return defaultValue;
}
if (n < 0) {
swift::warning(RuntimeErrorFlagNone,
"Warning: %s=%s out of bounds, clamping to 0.\n",
name, value);
return 0;
}
if (n > UINT32_MAX) {
swift::warning(RuntimeErrorFlagNone,
"Warning: %s=%s out of bounds, clamping to %" PRIu32 ".\n",
name, value, UINT32_MAX);
return UINT32_MAX;
}
return n;
}
static const char *parse_string(const char *name, const char *value,
const char *defaultValue) {
if (!value || value[0] == 0)
return strdup(defaultValue);
return strdup(value);
}
// Print a list of all the environment variables. Lazy initialization makes
// this a bit odd, but the use of these variables in the metadata system means
// it's almost certain to run early.
//
// The "extra" parameter is printed after the header and before the list of
// variables.
void printHelp(const char *extra) {
swift::warning(RuntimeErrorFlagNone, "Swift runtime debugging:\n");
if (extra)
swift::warning(RuntimeErrorFlagNone, "%s\n", extra);
#define VARIABLE(name, type, defaultValue, help) \
swift::warning(RuntimeErrorFlagNone, "%7s %s [default: %s] - %s\n", \
#type, #name, #defaultValue, help);
#include "EnvironmentVariables.def"
swift::warning(RuntimeErrorFlagNone, "SWIFT_DEBUG_HELP=YES - Print this help.");
}
#endif // SWIFT_STDLIB_HAS_ENVIRON
} // end anonymous namespace
// Define backing variables.
#define VARIABLE(name, type, defaultValue, help) \
swift::runtime::environment::types::type \
swift::runtime::environment::name##_variable = defaultValue; \
bool swift::runtime::environment::name##_isSet_variable = false;
#include "EnvironmentVariables.def"
// Initialization code.
swift::once_t swift::runtime::environment::initializeToken;
#if SWIFT_STDLIB_HAS_ENVIRON
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__)
extern "C" char **environ;
#define ENVIRON environ
#elif defined(_WIN32)
// `_environ` is DLL-imported unless we are linking against the static C runtime
// (via `/MT` or `/MTd`).
#if defined(_DLL)
extern "C" __declspec(dllimport) char **_environ;
#else
extern "C" char **_environ;
#endif
// `_environ` is unavailable in the Windows Runtime environment.
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/environ-wenviron?view=msvc-160
#if !defined(_WINRT_DLL)
#define ENVIRON _environ
#endif
#endif
#if defined(__ANDROID__)
// On Android, also try loading runtime debug env variables from system props.
static void platformInitialize(void *context) {
(void)context;
char buffer[PROP_VALUE_MAX] = "";
// Only system properties prefixed with "debug." can be set without root access.
#define SYSPROP_PREFIX "debug.org.swift.runtime."
#define VARIABLE(name, type, defaultValue, help) \
if (__system_property_get(SYSPROP_PREFIX #name, buffer)) { \
swift::runtime::environment::name##_isSet_variable = true; \
swift::runtime::environment::name##_variable = \
parse_##type(#name, buffer, defaultValue); \
}
#include "EnvironmentVariables.def"
#undef VARIABLE
}
#else
static void platformInitialize(void *context) {
(void)context;
}
#endif
#endif
#if SWIFT_STDLIB_HAS_ENVIRON
#if defined(ENVIRON)
void swift::runtime::environment::initialize(void *context) {
// On platforms where we have an environment variable array available, scan it
// directly. This optimizes for the common case where no variables are set,
// since we only need to perform one scan to set all variables. It also allows
// us to detect some spelling mistakes by warning on unknown SWIFT_ variables.
bool SWIFT_DEBUG_HELP_variable = false;
// Placeholder variable, we never use the result but the macros want to write
// to it.
bool SWIFT_DEBUG_HELP_isSet_variable = false;
(void)SWIFT_DEBUG_HELP_isSet_variable; // Silence warnings about unused vars.
for (char **var = ENVIRON; *var; var++) {
// Immediately skip anything without a SWIFT_ prefix.
if (strncmp(*var, "SWIFT_", 6) != 0)
continue;
bool foundVariable = false;
// Check each defined variable in turn, plus SWIFT_DEBUG_HELP. Variables are
// parsed by functions named parse_<type> above. An unknown type will
// produce an error that parse_<unknown-type> doesn't exist. Add new parsers
// above.
#define VARIABLE(name, type, defaultValue, help) \
if (strncmp(*var, #name "=", strlen(#name "=")) == 0) { \
name##_variable = \
parse_##type(#name, *var + strlen(#name "="), defaultValue); \
name##_isSet_variable = true; \
foundVariable = true; \
}
// SWIFT_DEBUG_HELP is not in the variables list. Parse it like the other
// variables.
VARIABLE(SWIFT_DEBUG_HELP, boolean, false, )
#include "EnvironmentVariables.def"
// Flag unknown SWIFT_DEBUG_ variables to catch misspellings. We don't flag
// all unknown SWIFT_ variables, because there are a bunch of other SWIFT_
// variables used for other purposes, such as SWIFT_SOURCE_ROOT and
// SWIFT_INSTALL_DIR, and we don't want to warn for all of those.
const char *swiftDebugPrefix = "SWIFT_DEBUG_";
if (!foundVariable &&
strncmp(*var, swiftDebugPrefix, strlen(swiftDebugPrefix)) == 0) {
const char *equals = strchr(*var, '=');
if (!equals)
equals = *var + strlen(*var);
swift::warning(RuntimeErrorFlagNone,
"Warning: unknown environment variable %.*s\n",
(int)(equals - *var), *var);
}
}
platformInitialize(context);
if (SWIFT_DEBUG_HELP_variable)
printHelp(nullptr);
}
#else
void swift::runtime::environment::initialize(void *context) {
// Emit a getenv call for each variable. This is less efficient but works
// everywhere.
#define VARIABLE(name, type, defaultValue, help) \
do { \
const char *name##_string = getenv(#name); \
if (name##_string) \
name##_isSet_variable = true; \
name##_variable = parse_##type(#name, name##_string, defaultValue); \
} while (0);
#include "EnvironmentVariables.def"
platformInitialize(context);
// Print help if requested.
if (parse_boolean("SWIFT_DEBUG_HELP", getenv("SWIFT_DEBUG_HELP"), false))
printHelp("Using getenv to read variables. Unknown SWIFT_DEBUG_ variables "
"will not be flagged.");
}
#endif
#else
void swift::runtime::environment::initialize(void *context) {
}
#endif
SWIFT_RUNTIME_EXPORT
bool swift_COWChecksEnabled() {
return runtime::environment::SWIFT_DEBUG_ENABLE_COW_CHECKS();
}
SWIFT_RUNTIME_STDLIB_SPI bool concurrencyEnableCooperativeQueues() {
return runtime::environment::
SWIFT_DEBUG_CONCURRENCY_ENABLE_COOPERATIVE_QUEUES();
}
SWIFT_RUNTIME_STDLIB_SPI bool concurrencyValidateUncheckedContinuations() {
return runtime::environment::SWIFT_DEBUG_VALIDATE_UNCHECKED_CONTINUATIONS();
}
SWIFT_RUNTIME_STDLIB_SPI const char *concurrencyIsCurrentExecutorLegacyModeOverride() {
return runtime::environment::SWIFT_IS_CURRENT_EXECUTOR_LEGACY_MODE_OVERRIDE();
}
SWIFT_RUNTIME_STDLIB_SPI bool concurrencyEnableTaskSlabAllocator() {
return runtime::environment::SWIFT_DEBUG_ENABLE_TASK_SLAB_ALLOCATOR();
}
SWIFT_RUNTIME_STDLIB_SPI const char *concurrencyTracingSubsystem() {
return runtime::environment::SWIFT_CONCURRENCY_TRACING_SUBSYSTEM();
}