Source File
godebug.go
Belonging Package
internal/godebug
// Copyright 2021 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// Package godebug makes the settings in the $GODEBUG environment variable// available to other packages. These settings are often used for compatibility// tweaks, when we need to change a default behavior but want to let users// opt back in to the original. For example GODEBUG=http2server=0 disables// HTTP/2 support in the net/http server.//// In typical usage, code should declare a Setting as a global// and then call Value each time the current setting value is needed://// var http2server = godebug.New("http2server")//// func ServeConn(c net.Conn) {// if http2server.Value() == "0" {// disallow HTTP/2// ...// }// ...// }//// Each time a non-default setting causes a change in program behavior,// code must call [Setting.IncNonDefault] to increment a counter that can// be reported by [runtime/metrics.Read]. The call must only happen when// the program executes a non-default behavior, not just when the setting// is set to a non-default value. This is occasionally (but very rarely)// infeasible, in which case the internal/godebugs table entry must set// Opaque: true, and the documentation in doc/godebug.md should// mention that metrics are unavailable.//// Conventionally, the global variable representing a godebug is named// for the godebug itself, with no case changes://// var gotypesalias = godebug.New("gotypesalias") // this// var goTypesAlias = godebug.New("gotypesalias") // NOT THIS//// The test in internal/godebugs that checks for use of IncNonDefault// requires the use of this convention.//// Note that counters used with IncNonDefault must be added to// various tables in other packages. See the [Setting.IncNonDefault]// documentation for details.package godebug// Note: Be careful about new imports here. Any package// that internal/godebug imports cannot itself import internal/godebug,// meaning it cannot introduce a GODEBUG setting of its own.// We keep imports to the absolute bare minimum.import (_ // go:linkname)// A Setting is a single setting in the $GODEBUG environment variable.type Setting struct {name stringonce sync.Once*setting}type setting struct {value atomic.Pointer[value]nonDefaultOnce sync.OncenonDefault atomic.Uint64info *godebugs.Info}type value struct {text stringbisect *bisect.Matcher}// New returns a new Setting for the $GODEBUG setting with the given name.//// GODEBUGs meant for use by end users must be listed in ../godebugs/table.go,// which is used for generating and checking various documentation.// If the name is not listed in that table, New will succeed but calling Value// on the returned Setting will panic.// To disable that panic for access to an undocumented setting,// prefix the name with a #, as in godebug.New("#gofsystrace").// The # is a signal to New but not part of the key used in $GODEBUG.//// Note that almost all settings should arrange to call [IncNonDefault] precisely// when program behavior is changing from the default due to the setting// (not just when the setting is different, but when program behavior changes).// See the [internal/godebug] package comment for more.func ( string) *Setting {return &Setting{name: }}// Name returns the name of the setting.func ( *Setting) () string {if .name != "" && .name[0] == '#' {return .name[1:]}return .name}// Undocumented reports whether this is an undocumented setting.func ( *Setting) () bool {return .name != "" && .name[0] == '#'}// String returns a printable form for the setting: name=value.func ( *Setting) () string {return .Name() + "=" + .Value()}// IncNonDefault increments the non-default behavior counter// associated with the given setting.// This counter is exposed in the runtime/metrics value// /godebug/non-default-behavior/<name>:events.//// Note that Value must be called at least once before IncNonDefault.func ( *Setting) () {.nonDefaultOnce.Do(.register).nonDefault.Add(1)}func ( *Setting) () {if .info == nil || .info.Opaque {panic("godebug: unexpected IncNonDefault of " + .name)}registerMetric("/godebug/non-default-behavior/"+.Name()+":events", .nonDefault.Load)}// cache is a cache of all the GODEBUG settings,// a locked map[string]*atomic.Pointer[string].//// All Settings with the same name share a single// *atomic.Pointer[string], so that when GODEBUG// changes only that single atomic string pointer// needs to be updated.//// A name appears in the values map either if it is the// name of a Setting for which Value has been called// at least once, or if the name has ever appeared in// a name=value pair in the $GODEBUG environment variable.// Once entered into the map, the name is never removed.var cache sync.Map // name string -> value *atomic.Pointer[string]var empty value// Value returns the current value for the GODEBUG setting s.//// Value maintains an internal cache that is synchronized// with changes to the $GODEBUG environment variable,// making Value efficient to call as frequently as needed.// Clients should therefore typically not attempt their own// caching of Value's result.func ( *Setting) () string {.once.Do(func() {.setting = lookup(.Name())if .info == nil && !.Undocumented() {panic("godebug: Value of name not listed in godebugs.All: " + .name)}}):= *.value.Load()if .bisect != nil && !.bisect.Stack(&stderr) {return ""}return .text}// lookup returns the unique *setting value for the given name.func ( string) *setting {if , := cache.Load(); {return .(*setting)}:= new(setting).info = godebugs.Lookup().value.Store(&empty)if , := cache.LoadOrStore(, ); {// Lost race: someone else created it. Use theirs.return .(*setting)}return}// setUpdate is provided by package runtime.// It calls update(def, env), where def is the default GODEBUG setting// and env is the current value of the $GODEBUG environment variable.// After that first call, the runtime calls update(def, env)// again each time the environment variable changes// (due to use of os.Setenv, for example).////go:linkname setUpdatefunc ( func(string, string))// registerMetric is provided by package runtime.// It forwards registrations to runtime/metrics.////go:linkname registerMetricfunc ( string, func() uint64)// setNewIncNonDefault is provided by package runtime.// The runtime can do//// inc := newNonDefaultInc(name)//// instead of//// inc := godebug.New(name).IncNonDefault//// since it cannot import godebug.////go:linkname setNewIncNonDefaultfunc ( func(string) func())func () {setUpdate(update)setNewIncNonDefault(newIncNonDefault)}func ( string) func() {:= New().Value()return .IncNonDefault}var updateMu sync.Mutex// update records an updated GODEBUG setting.// def is the default GODEBUG setting for the running binary,// and env is the current value of the $GODEBUG environment variable.func (, string) {updateMu.Lock()defer updateMu.Unlock()// Update all the cached values, creating new ones as needed.// We parse the environment variable first, so that any settings it has// are already locked in place (did[name] = true) before we consider// the defaults.:= make(map[string]bool)parse(, )parse(, )// Clear any cached values that are no longer present.cache.Range(func(, any) bool {if ![.(string)] {.(*setting).value.Store(&empty)}return true})}// parse parses the GODEBUG setting string s,// which has the form k=v,k2=v2,k3=v3.// Later settings override earlier ones.// Parse only updates settings k=v for which did[k] = false.// It also sets did[k] = true for settings that it updates.// Each value v can also have the form v#pattern,// in which case the GODEBUG is only enabled for call stacks// matching pattern, for use with golang.org/x/tools/cmd/bisect.func ( map[string]bool, string) {// Scan the string backward so that later settings are used// and earlier settings are ignored.// Note that a forward scan would cause cached values// to temporarily use the ignored value before being// updated to the "correct" one.:= len():= -1for := - 1; >= -1; -- {if == -1 || [] == ',' {if >= 0 {, := [+1:], [+1:]if ![] {[] = true:= &value{text: }for := 0; < len(); ++ {if [] == '#' {.text = [:].bisect, _ = bisect.New([+1:])break}}lookup().value.Store()}}= -1=} else if [] == '=' {=}}}type runtimeStderr struct{}var stderr runtimeStderrfunc (*runtimeStderr) ( []byte) (int, error) {if len() > 0 {write(2, unsafe.Pointer(&[0]), int32(len()))}return len(), nil}// Since we cannot import os or syscall, use the runtime's write function// to print to standard error.////go:linkname write runtime.writefunc ( uintptr, unsafe.Pointer, int32) int32
The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64)