github.com/bir3/gocompiler@v0.9.2202/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 // 24 // Each time a non-default setting causes a change in program behavior, 25 // code should call [Setting.IncNonDefault] to increment a counter that can 26 // be reported by [runtime/metrics.Read]. 27 // Note that counters used with IncNonDefault must be added to 28 // various tables in other packages. See the [Setting.IncNonDefault] 29 // documentation for details. 30 package godebug 31 32 // Note: Be careful about new imports here. Any package 33 // that internal/godebug imports cannot itself import internal/godebug, 34 // meaning it cannot introduce a GODEBUG setting of its own. 35 // We keep imports to the absolute bare minimum. 36 import ( 37 "github.com/bir3/gocompiler/src/internal/bisect" 38 "github.com/bir3/gocompiler/src/internal/godebugs" 39 "sync" 40 "sync/atomic" 41 "unsafe" 42 _ "unsafe" // go:linkname 43 ) 44 45 // A Setting is a single setting in the $GODEBUG environment variable. 46 type Setting struct { 47 name string 48 once sync.Once 49 *setting 50 } 51 52 type setting struct { 53 value atomic.Pointer[value] 54 nonDefaultOnce sync.Once 55 nonDefault atomic.Uint64 56 info *godebugs.Info 57 } 58 59 type value struct { 60 text string 61 bisect *bisect.Matcher 62 } 63 64 // New returns a new Setting for the $GODEBUG setting with the given name. 65 // 66 // GODEBUGs meant for use by end users must be listed in ../godebugs/table.go, 67 // which is used for generating and checking various documentation. 68 // If the name is not listed in that table, New will succeed but calling Value 69 // on the returned Setting will panic. 70 // To disable that panic for access to an undocumented setting, 71 // prefix the name with a #, as in godebug.New("#gofsystrace"). 72 // The # is a signal to New but not part of the key used in $GODEBUG. 73 func New(name string) *Setting { 74 return &Setting{name: name} 75 } 76 77 // Name returns the name of the setting. 78 func (s *Setting) Name() string { 79 if s.name != "" && s.name[0] == '#' { 80 return s.name[1:] 81 } 82 return s.name 83 } 84 85 // Undocumented reports whether this is an undocumented setting. 86 func (s *Setting) Undocumented() bool { 87 return s.name != "" && s.name[0] == '#' 88 } 89 90 // String returns a printable form for the setting: name=value. 91 func (s *Setting) String() string { 92 return s.Name() + "=" + s.Value() 93 } 94 95 // IncNonDefault increments the non-default behavior counter 96 // associated with the given setting. 97 // This counter is exposed in the runtime/metrics value 98 // /godebug/non-default-behavior/<name>:events. 99 // 100 // Note that Value must be called at least once before IncNonDefault. 101 func (s *Setting) IncNonDefault() { 102 s.nonDefaultOnce.Do(s.register) 103 s.nonDefault.Add(1) 104 } 105 106 func (s *Setting) register() { 107 if s.info == nil || s.info.Opaque { 108 panic("godebug: unexpected IncNonDefault of " + s.name) 109 } 110 registerMetric("/godebug/non-default-behavior/"+s.Name()+":events", s.nonDefault.Load) 111 } 112 113 // cache is a cache of all the GODEBUG settings, 114 // a locked map[string]*atomic.Pointer[string]. 115 // 116 // All Settings with the same name share a single 117 // *atomic.Pointer[string], so that when GODEBUG 118 // changes only that single atomic string pointer 119 // needs to be updated. 120 // 121 // A name appears in the values map either if it is the 122 // name of a Setting for which Value has been called 123 // at least once, or if the name has ever appeared in 124 // a name=value pair in the $GODEBUG environment variable. 125 // Once entered into the map, the name is never removed. 126 var cache sync.Map // name string -> value *atomic.Pointer[string] 127 128 var empty value 129 130 // Value returns the current value for the GODEBUG setting s. 131 // 132 // Value maintains an internal cache that is synchronized 133 // with changes to the $GODEBUG environment variable, 134 // making Value efficient to call as frequently as needed. 135 // Clients should therefore typically not attempt their own 136 // caching of Value's result. 137 func (s *Setting) Value() string { 138 s.once.Do(func() { 139 s.setting = lookup(s.Name()) 140 if s.info == nil && !s.Undocumented() { 141 panic("godebug: Value of name not listed in godebugs.All: " + s.name) 142 } 143 }) 144 v := *s.value.Load() 145 if v.bisect != nil && !v.bisect.Stack(&stderr) { 146 return "" 147 } 148 return v.text 149 } 150 151 // lookup returns the unique *setting value for the given name. 152 func lookup(name string) *setting { 153 if v, ok := cache.Load(name); ok { 154 return v.(*setting) 155 } 156 s := new(setting) 157 s.info = godebugs.Lookup(name) 158 s.value.Store(&empty) 159 if v, loaded := cache.LoadOrStore(name, s); loaded { 160 // Lost race: someone else created it. Use theirs. 161 return v.(*setting) 162 } 163 164 return s 165 } 166 167 // setUpdate is provided by package runtime. 168 // It calls update(def, env), where def is the default GODEBUG setting 169 // and env is the current value of the $GODEBUG environment variable. 170 // After that first call, the runtime calls update(def, env) 171 // again each time the environment variable changes 172 // (due to use of os.Setenv, for example). 173 // 174 //go:linkname setUpdate internal/godebug.setUpdate 175 func setUpdate(update func(string, string)) 176 177 // registerMetric is provided by package runtime. 178 // It forwards registrations to runtime/metrics. 179 // 180 //go:linkname registerMetric internal/godebug.registerMetric 181 func registerMetric(name string, read func() uint64) 182 183 // setNewIncNonDefault is provided by package runtime. 184 // The runtime can do 185 // 186 // inc := newNonDefaultInc(name) 187 // 188 // instead of 189 // 190 // inc := godebug.New(name).IncNonDefault 191 // 192 // since it cannot import godebug. 193 // 194 //go:linkname setNewIncNonDefault internal/godebug.setNewIncNonDefault 195 func setNewIncNonDefault(newIncNonDefault func(string) func()) 196 197 func init() { 198 setUpdate(update) 199 setNewIncNonDefault(newIncNonDefault) 200 } 201 202 func newIncNonDefault(name string) func() { 203 s := New(name) 204 s.Value() 205 return s.IncNonDefault 206 } 207 208 var updateMu sync.Mutex 209 210 // update records an updated GODEBUG setting. 211 // def is the default GODEBUG setting for the running binary, 212 // and env is the current value of the $GODEBUG environment variable. 213 func update(def, env string) { 214 updateMu.Lock() 215 defer updateMu.Unlock() 216 217 // Update all the cached values, creating new ones as needed. 218 // We parse the environment variable first, so that any settings it has 219 // are already locked in place (did[name] = true) before we consider 220 // the defaults. 221 did := make(map[string]bool) 222 parse(did, env) 223 parse(did, def) 224 225 // Clear any cached values that are no longer present. 226 cache.Range(func(name, s any) bool { 227 if !did[name.(string)] { 228 s.(*setting).value.Store(&empty) 229 } 230 return true 231 }) 232 } 233 234 // parse parses the GODEBUG setting string s, 235 // which has the form k=v,k2=v2,k3=v3. 236 // Later settings override earlier ones. 237 // Parse only updates settings k=v for which did[k] = false. 238 // It also sets did[k] = true for settings that it updates. 239 // Each value v can also have the form v#pattern, 240 // in which case the GODEBUG is only enabled for call stacks 241 // matching pattern, for use with golang.org/x/tools/cmd/bisect. 242 func parse(did map[string]bool, s string) { 243 // Scan the string backward so that later settings are used 244 // and earlier settings are ignored. 245 // Note that a forward scan would cause cached values 246 // to temporarily use the ignored value before being 247 // updated to the "correct" one. 248 end := len(s) 249 eq := -1 250 for i := end - 1; i >= -1; i-- { 251 if i == -1 || s[i] == ',' { 252 if eq >= 0 { 253 name, arg := s[i+1:eq], s[eq+1:end] 254 if !did[name] { 255 did[name] = true 256 v := &value{text: arg} 257 for j := 0; j < len(arg); j++ { 258 if arg[j] == '#' { 259 v.text = arg[:j] 260 v.bisect, _ = bisect.New(arg[j+1:]) 261 break 262 } 263 } 264 lookup(name).value.Store(v) 265 } 266 } 267 eq = -1 268 end = i 269 } else if s[i] == '=' { 270 eq = i 271 } 272 } 273 } 274 275 type runtimeStderr struct{} 276 277 var stderr runtimeStderr 278 279 func (*runtimeStderr) Write(b []byte) (int, error) { 280 if len(b) > 0 { 281 write(2, unsafe.Pointer(&b[0]), int32(len(b))) 282 } 283 return len(b), nil 284 } 285 286 // Since we cannot import os or syscall, use the runtime's write function 287 // to print to standard error. 288 // 289 //go:linkname write runtime.write 290 func write(fd uintptr, p unsafe.Pointer, n int32) int32