github.com/bir3/gocompiler@v0.3.205/src/internal/godebug/godebug.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package godebug makes the settings in the $GODEBUG environment variable 6 // available to other packages. These settings are often used for compatibility 7 // tweaks, when we need to change a default behavior but want to let users 8 // opt back in to the original. For example GODEBUG=http2server=0 disables 9 // HTTP/2 support in the net/http server. 10 // 11 // In typical usage, code should declare a Setting as a global 12 // and then call Value each time the current setting value is needed: 13 // 14 // var http2server = godebug.New("http2server") 15 // 16 // func ServeConn(c net.Conn) { 17 // if http2server.Value() == "0" { 18 // disallow HTTP/2 19 // ... 20 // } 21 // ... 22 // } 23 package godebug 24 25 import ( 26 "sync" 27 "sync/atomic" 28 _ "unsafe" // go:linkname 29 ) 30 31 // A Setting is a single setting in the $GODEBUG environment variable. 32 type Setting struct { 33 name string 34 once sync.Once 35 value *atomic.Pointer[string] 36 } 37 38 // New returns a new Setting for the $GODEBUG setting with the given name. 39 func New(name string) *Setting { 40 return &Setting{name: name} 41 } 42 43 // Name returns the name of the setting. 44 func (s *Setting) Name() string { 45 return s.name 46 } 47 48 // String returns a printable form for the setting: name=value. 49 func (s *Setting) String() string { 50 return s.name + "=" + s.Value() 51 } 52 53 // cache is a cache of all the GODEBUG settings, 54 // a locked map[string]*atomic.Pointer[string]. 55 // 56 // All Settings with the same name share a single 57 // *atomic.Pointer[string], so that when GODEBUG 58 // changes only that single atomic string pointer 59 // needs to be updated. 60 // 61 // A name appears in the values map either if it is the 62 // name of a Setting for which Value has been called 63 // at least once, or if the name has ever appeared in 64 // a name=value pair in the $GODEBUG environment variable. 65 // Once entered into the map, the name is never removed. 66 var cache sync.Map // name string -> value *atomic.Pointer[string] 67 68 var empty string 69 70 // Value returns the current value for the GODEBUG setting s. 71 // 72 // Value maintains an internal cache that is synchronized 73 // with changes to the $GODEBUG environment variable, 74 // making Value efficient to call as frequently as needed. 75 // Clients should therefore typically not attempt their own 76 // caching of Value's result. 77 func (s *Setting) Value() string { 78 s.once.Do(func() { 79 v, ok := cache.Load(s.name) 80 if !ok { 81 p := new(atomic.Pointer[string]) 82 p.Store(&empty) 83 v, _ = cache.LoadOrStore(s.name, p) 84 } 85 s.value = v.(*atomic.Pointer[string]) 86 }) 87 return *s.value.Load() 88 } 89 90 // setUpdate is provided by package runtime. 91 // It calls update(def, env), where def is the default GODEBUG setting 92 // and env is the current value of the $GODEBUG environment variable. 93 // After that first call, the runtime calls update(def, env) 94 // again each time the environment variable changes 95 // (due to use of os.Setenv, for example). 96 // 97 //go:linkname setUpdate internal/godebug.setUpdate 98 func setUpdate(update func(string, string)) 99 100 func init() { 101 setUpdate(update) 102 } 103 104 var updateMu sync.Mutex 105 106 // update records an updated GODEBUG setting. 107 // def is the default GODEBUG setting for the running binary, 108 // and env is the current value of the $GODEBUG environment variable. 109 func update(def, env string) { 110 updateMu.Lock() 111 defer updateMu.Unlock() 112 113 // Update all the cached values, creating new ones as needed. 114 // We parse the environment variable first, so that any settings it has 115 // are already locked in place (did[name] = true) before we consider 116 // the defaults. 117 did := make(map[string]bool) 118 parse(did, env) 119 parse(did, def) 120 121 // Clear any cached values that are no longer present. 122 cache.Range(func(name, v any) bool { 123 if !did[name.(string)] { 124 v.(*atomic.Pointer[string]).Store(&empty) 125 } 126 return true 127 }) 128 } 129 130 // parse parses the GODEBUG setting string s, 131 // which has the form k=v,k2=v2,k3=v3. 132 // Later settings override earlier ones. 133 // Parse only updates settings k=v for which did[k] = false. 134 // It also sets did[k] = true for settings that it updates. 135 func parse(did map[string]bool, s string) { 136 // Scan the string backward so that later settings are used 137 // and earlier settings are ignored. 138 // Note that a forward scan would cause cached values 139 // to temporarily use the ignored value before being 140 // updated to the "correct" one. 141 end := len(s) 142 eq := -1 143 for i := end - 1; i >= -1; i-- { 144 if i == -1 || s[i] == ',' { 145 if eq >= 0 { 146 name, value := s[i+1:eq], s[eq+1:end] 147 if !did[name] { 148 did[name] = true 149 v, ok := cache.Load(name) 150 if !ok { 151 p := new(atomic.Pointer[string]) 152 p.Store(&empty) 153 v, _ = cache.LoadOrStore(name, p) 154 } 155 v.(*atomic.Pointer[string]).Store(&value) 156 } 157 } 158 eq = -1 159 end = i 160 } else if s[i] == '=' { 161 eq = i 162 } 163 } 164 }