1/*
2 * Copyright (c) 2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * @APPLE_APACHE_LICENSE_HEADER_END@
19 */
20/*
21    Environment.cpp
22    Environment Variables
23    Copyright (c) 2004-2011 Apple Inc. All rights reserved.
24 */
25
26#include <errno.h>
27#include <crt_externs.h>
28
29#include "Definitions.h"
30#include "Environment.h"
31#ifndef AUTO_TESTER
32#include "auto_impl_utilities.h"
33#endif
34
35namespace Auto {
36#if defined(DEBUG)
37    bool Environment::clear_all_new;                          // clear all new blocks
38    bool Environment::dirty_all_new;                          // dirty all new blocks
39    bool Environment::print_stats;                            // print statistics after collection
40    bool Environment::print_scan_stats;                       // print scanning statistics
41    bool Environment::print_allocs;                           // print vm and malloc allocations and deallocations
42    bool Environment::unscanned_store_warning;                // warn when GC-managed pointers stored in unscanned memory.
43#endif
44
45    bool Environment::guard_pages;                            // create guard pages for all small/medium blocks.
46    bool Environment::dirty_all_deleted;                      // dirty all deleted blocks
47    bool Environment::thread_collections;                     // enable thread local collections
48    bool Environment::log_reference_counting;                 // log reference counting activity
49    bool Environment::log_compactions;                        // log compaction activity
50    bool Environment::scramble_heap;                          // move all possible objects during compaction
51    uint32_t Environment::exhaustive_collection_limit;        // max # of full collections in an exhaustive collection
52    bool Environment::resurrection_is_fatal;                  // true if resurrection is a fatal error
53    bool Environment::environ_has_auto_prefix;                // true if any strings in environ have the AUTO_ prefix.
54    bool Environment::environ_has_malloc_prefix;              // true if any strings in environ have the Malloc prefix.
55    double Environment::default_duty_cycle;                   // default collector duty cycle.
56
57
58    const char *Environment::get(const char *name) {
59        if ((environ_has_auto_prefix && strncmp(name, "AUTO_", 5) == 0) ||
60            (environ_has_malloc_prefix && strncmp(name, "Malloc", 5) == 0)) {
61                return ::getenv(name);
62        }
63        return NULL;
64    }
65
66    //
67    // read_long
68    //
69    // Read a long (integer) value from the environment variable given by var.
70    // Return the value, or returns default_value if var is unset.
71    // msg is an optional descriptive message indicating the effect of a non-default value for var
72    //
73    long Environment::read_long(const char *var, long default_value, const char *msg) {
74        long result = default_value;
75        const char *s = Environment::get(var);
76        if (s) {
77            long parsed = strtol(s, NULL, 10);
78            if (parsed != 0 || errno != EINVAL) {
79                result = parsed;
80#ifndef AUTO_TESTER
81                if (result != default_value)
82                    malloc_printf("%s: %s = \"%s\" in environment. %s\n", auto_prelude(), var, s, msg ?: "");
83#endif
84            }
85        }
86        return result;
87    }
88
89    //
90    // read_bool
91    //
92    // Read a boolean value from the environment variable given by var.
93    // Returns default_value if var is not set in the environment.
94    // Returns true if var is set to an empty string
95    // Returns true if var is set to "yes" or "true" (case insensitive).
96    // Returns false if var is set to "no" or "false".
97    // msg is an optional descriptive message indicating the effect of a non-default value for var
98    //
99    bool Environment::read_bool(const char *var, bool default_value, const char *msg) {
100        bool result = default_value;
101        const char *s = Environment::get(var);
102        if (s) {
103            if (strlen(s) == 0)
104                result = true;
105            else if (strcasecmp(s, "yes") == 0 || strcasecmp(s, "true") == 0 || strcmp(s, "1") == 0)
106                result = true;
107            else if (strcasecmp(s, "no") == 0 || strcasecmp(s, "false") == 0 || strcmp(s, "0") == 0)
108                result = false;
109#ifndef AUTO_TESTER
110            if (result != default_value)
111                malloc_printf("%s: %s = \"%s\" in environment. %s\n", auto_prelude(), var, s, msg ?: "");
112#endif
113        }
114        return result;
115    }
116
117    static void prescan_environment() {
118        for (char **env = *_NSGetEnviron(); *env != NULL; ++env) {
119            if (strncmp(*env, "AUTO_", 5) == 0)
120                Environment::environ_has_auto_prefix = true;
121            else if (strncmp(*env, "Malloc", 6) == 0)
122                Environment::environ_has_malloc_prefix = true;
123        }
124    }
125
126    //
127    // initialize
128    //
129    // Reads the environment variables values.
130    //
131    void Environment::initialize() {
132        prescan_environment();
133
134#if defined(DEBUG)
135        clear_all_new     = read_bool("AUTO_CLEAR_ALL_NEW", false);
136        dirty_all_new     = read_bool("AUTO_DIRTY_ALL_NEW", false);
137        print_stats       = read_bool("AUTO_PRINT_STATS", false);
138        print_scan_stats  = read_bool("AUTO_SCAN_PRINT_STATS", false);
139        unscanned_store_warning = read_bool("AUTO_UNSCANNED_STORE_WARNING", false, "Unscanned store warnings enabled.");
140#endif
141        guard_pages       = read_bool("AUTO_USE_GUARDS", false, "Guard pages are enabled.  Application will be slower and use more memory. Buffer overruns in the Auto zone will be caught.");
142        dirty_all_deleted = read_bool("AUTO_DIRTY_ALL_DELETED", false, "Deleted objects will be dirtied by the collector (similar to MallocScribble).") || read_long("MallocScribble", false, "Deleted objects will be dirtied by the collector.");
143        thread_collections = read_bool("AUTO_USE_TLC", true, "Thread local collector [TLC] disabled.");
144        log_reference_counting = read_bool("AUTO_REFERENCE_COUNT_LOGGING", false, "Reference count logging enabled.");
145        log_compactions = read_bool("AUTO_COMPACTION_LOGGING", false, "Compaction logging enabled.");
146        scramble_heap = read_bool("AUTO_COMPACTION_SCRAMBLE", false, "Heap scrambling enabled.");
147        exhaustive_collection_limit = read_long("AUTO_EXHAUSTIVE_COLLECTION_LIMIT", 8);
148        resurrection_is_fatal = read_bool("AUTO_RESURRECTION_ABORT", true, "Resurrections errors will not be treated as fatal. This may lead to heap inconsistencies and crashes, possibly long after the resurrection occurs.");
149        default_duty_cycle = (double)read_long("AUTO_DUTY_CYCLE", 25) / 100.0;
150        if (default_duty_cycle < 0.0001 || default_duty_cycle > 1.0) {
151            default_duty_cycle = 0.25;
152#ifndef AUTO_TESTER
153            malloc_printf("%s: Invalid value for AUTO_DUTY_CYCLE. Using default.\n", auto_prelude());
154#endif
155        }
156    }
157}
158