aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2022-11-11 12:36:31 -0500
committerGopher Robot <gobot@golang.org>2022-11-14 15:19:57 +0000
commitea4631cc0cf301c824bd665a7980c13289ab5c9d (patch)
tree78c1ee219438b55df5da49575bf4cbbefe590f1e /src/runtime
parent40bdcbb483548c0b660503c3ba80f9676b98fd5f (diff)
downloadgo-ea4631cc0cf301c824bd665a7980c13289ab5c9d.tar.xz
internal/godebug: define more efficient API
We have been expanding our use of GODEBUG for compatibility, and the current implementation forces a tradeoff between freshness and efficiency. It parses the environment variable in full each time it is called, which is expensive. But if clients cache the result, they won't respond to run-time GODEBUG changes, as happened with x509sha1 (#56436). This CL changes the GODEBUG API to provide efficient, up-to-date results. Instead of a single Get function, New returns a *godebug.Setting that itself has a Get method. Clients can save the result of New, which is no more expensive than errors.New, in a global variable, and then call that variable's Get method to get the value. Get costs only two atomic loads in the case where the variable hasn't changed since the last call. Unfortunately, these changes do require importing sync from godebug, which will mean that sync itself will never be able to use a GODEBUG setting. That doesn't seem like such a hardship. If it was really necessary, the runtime could pass a setting to package sync itself at startup, with the caveat that that setting, like the ones used by runtime itself, would not respond to run-time GODEBUG changes. Change-Id: I99a3acfa24fb2a692610af26a5d14bbc62c966ac Reviewed-on: https://go-review.googlesource.com/c/go/+/449504 Run-TryBot: Russ Cox <rsc@golang.org> Auto-Submit: Russ Cox <rsc@golang.org> Reviewed-by: Michael Knyszek <mknyszek@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/runtime.go30
-rw-r--r--src/runtime/runtime1.go2
2 files changed, 23 insertions, 9 deletions
diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go
index bc60b3ca75..9f68738aa7 100644
--- a/src/runtime/runtime.go
+++ b/src/runtime/runtime.go
@@ -66,14 +66,26 @@ func syscall_Exit(code int) {
exit(int32(code))
}
-var godebugenv atomic.Pointer[string] // set by parsedebugvars
+var godebugDefault string
+var godebugUpdate atomic.Pointer[func(string, string)]
+var godebugEnv atomic.Pointer[string] // set by parsedebugvars
-//go:linkname godebug_getGODEBUG internal/godebug.getGODEBUG
-func godebug_getGODEBUG() string {
- if p := godebugenv.Load(); p != nil {
- return *p
+//go:linkname godebug_setUpdate internal/godebug.setUpdate
+func godebug_setUpdate(update func(string, string)) {
+ p := new(func(string, string))
+ *p = update
+ godebugUpdate.Store(p)
+ godebugNotify()
+}
+
+func godebugNotify() {
+ if update := godebugUpdate.Load(); update != nil {
+ var env string
+ if p := godebugEnv.Load(); p != nil {
+ env = *p
+ }
+ (*update)(godebugDefault, env)
}
- return ""
}
//go:linkname syscall_runtimeSetenv syscall.runtimeSetenv
@@ -82,7 +94,8 @@ func syscall_runtimeSetenv(key, value string) {
if key == "GODEBUG" {
p := new(string)
*p = value
- godebugenv.Store(p)
+ godebugEnv.Store(p)
+ godebugNotify()
}
}
@@ -90,7 +103,8 @@ func syscall_runtimeSetenv(key, value string) {
func syscall_runtimeUnsetenv(key string) {
unsetenv_c(key)
if key == "GODEBUG" {
- godebugenv.Store(nil)
+ godebugEnv.Store(nil)
+ godebugNotify()
}
}
diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go
index a29608329c..76dca9ca77 100644
--- a/src/runtime/runtime1.go
+++ b/src/runtime/runtime1.go
@@ -375,7 +375,7 @@ func parsedebugvars() {
}
globalGODEBUG = gogetenv("GODEBUG")
- godebugenv.StoreNoWB(&globalGODEBUG)
+ godebugEnv.StoreNoWB(&globalGODEBUG)
for p := globalGODEBUG; p != ""; {
field := ""
i := bytealg.IndexByteString(p, ',')