...

Source file src/internal/godebug/godebug.go

Documentation: internal/godebug

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

View as plain text