aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2023-01-12 20:25:39 -0800
committerKeith Randall <khr@golang.org>2023-04-14 16:55:22 +0000
commit2b92c39fe08101ed8c9f032d577df4cc882d08d7 (patch)
tree1446e0a68fa6fb81fdd141a241e8b818e6343151 /src/runtime
parentd4bcfe4e834da1d31b7071e83eb045e089271175 (diff)
downloadgo-2b92c39fe08101ed8c9f032d577df4cc882d08d7.tar.xz
cmd/link: establish dependable package initialization order
(This is a retry of CL 462035 which was reverted at 474976. The only change from that CL is the aix fix SRODATA->SNOPTRDATA at inittask.go:141) As described here: https://github.com/golang/go/issues/31636#issuecomment-493271830 "Find the lexically earliest package that is not initialized yet, but has had all its dependencies initialized, initialize that package, and repeat." Simplify the runtime a bit, by just computing the ordering required in the linker and giving a list to the runtime. Update #31636 Fixes #57411 RELNOTE=yes Change-Id: I28c09451d6aa677d7394c179d23c2c02c503fc56 Reviewed-on: https://go-review.googlesource.com/c/go/+/478916 Reviewed-by: Than McIntosh <thanm@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com> Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org>
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/plugin.go10
-rw-r--r--src/runtime/proc.go60
-rw-r--r--src/runtime/symtab.go4
3 files changed, 40 insertions, 34 deletions
diff --git a/src/runtime/plugin.go b/src/runtime/plugin.go
index a61dcc3b5d..312802de00 100644
--- a/src/runtime/plugin.go
+++ b/src/runtime/plugin.go
@@ -7,7 +7,7 @@ package runtime
import "unsafe"
//go:linkname plugin_lastmoduleinit plugin.lastmoduleinit
-func plugin_lastmoduleinit() (path string, syms map[string]any, errstr string) {
+func plugin_lastmoduleinit() (path string, syms map[string]any, initTasks []*initTask, errstr string) {
var md *moduledata
for pmd := firstmoduledata.next; pmd != nil; pmd = pmd.next {
if pmd.bad {
@@ -23,13 +23,13 @@ func plugin_lastmoduleinit() (path string, syms map[string]any, errstr string) {
throw("runtime: plugin has empty pluginpath")
}
if md.typemap != nil {
- return "", nil, "plugin already loaded"
+ return "", nil, nil, "plugin already loaded"
}
for _, pmd := range activeModules() {
if pmd.pluginpath == md.pluginpath {
md.bad = true
- return "", nil, "plugin already loaded"
+ return "", nil, nil, "plugin already loaded"
}
if inRange(pmd.text, pmd.etext, md.text, md.etext) ||
@@ -51,7 +51,7 @@ func plugin_lastmoduleinit() (path string, syms map[string]any, errstr string) {
for _, pkghash := range md.pkghashes {
if pkghash.linktimehash != *pkghash.runtimehash {
md.bad = true
- return "", nil, "plugin was built with a different version of package " + pkghash.modulename
+ return "", nil, nil, "plugin was built with a different version of package " + pkghash.modulename
}
}
@@ -90,7 +90,7 @@ func plugin_lastmoduleinit() (path string, syms map[string]any, errstr string) {
}
syms[name] = val
}
- return md.pluginpath, syms, ""
+ return md.pluginpath, syms, md.inittasks, ""
}
func pluginftabverify(md *moduledata) {
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 4152aa4852..90b6d81bf8 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -117,11 +117,9 @@ var (
raceprocctx0 uintptr
)
-//go:linkname runtime_inittask runtime..inittask
-var runtime_inittask initTask
-
-//go:linkname main_inittask main..inittask
-var main_inittask initTask
+// This slice records the initializing tasks that need to be
+// done to start up the runtime. It is built by the linker.
+var runtime_inittasks []*initTask
// main_init_done is a signal used by cgocallbackg that initialization
// has been completed. It is made before _cgo_notify_runtime_init_done,
@@ -196,7 +194,7 @@ func main() {
inittrace.active = true
}
- doInit(&runtime_inittask) // Must be before defer.
+ doInit(runtime_inittasks) // Must be before defer.
// Defer unlock so that runtime.Goexit during init does the unlock too.
needUnlock := true
@@ -241,7 +239,14 @@ func main() {
cgocall(_cgo_notify_runtime_init_done, nil)
}
- doInit(&main_inittask)
+ // Run the initializing tasks. Depending on build mode this
+ // list can arrive a few different ways, but it will always
+ // contain the init tasks computed by the linker for all the
+ // packages in the program (excluding those added at runtime
+ // by package plugin).
+ for _, m := range activeModules() {
+ doInit(m.inittasks)
+ }
// Disable init tracing after main init done to avoid overhead
// of collecting statistics in malloc and newproc
@@ -6520,14 +6525,11 @@ func gcd(a, b uint32) uint32 {
}
// An initTask represents the set of initializations that need to be done for a package.
-// Keep in sync with ../../test/initempty.go:initTask
+// Keep in sync with ../../test/noinit.go:initTask
type initTask struct {
- // TODO: pack the first 3 fields more tightly?
- state uintptr // 0 = uninitialized, 1 = in progress, 2 = done
- ndeps uintptr
- nfns uintptr
- // followed by ndeps instances of an *initTask, one per package depended on
- // followed by nfns pcs, one per init function to run
+ state uint32 // 0 = uninitialized, 1 = in progress, 2 = done
+ nfns uint32
+ // followed by nfns pcs, uintptr sized, one per init function to run
}
// inittrace stores statistics for init functions which are
@@ -6541,7 +6543,13 @@ type tracestat struct {
bytes uint64 // heap allocated bytes
}
-func doInit(t *initTask) {
+func doInit(ts []*initTask) {
+ for _, t := range ts {
+ doInit1(t)
+ }
+}
+
+func doInit1(t *initTask) {
switch t.state {
case 2: // fully initialized
return
@@ -6550,17 +6558,6 @@ func doInit(t *initTask) {
default: // not initialized yet
t.state = 1 // initialization in progress
- for i := uintptr(0); i < t.ndeps; i++ {
- p := add(unsafe.Pointer(t), (3+i)*goarch.PtrSize)
- t2 := *(**initTask)(p)
- doInit(t2)
- }
-
- if t.nfns == 0 {
- t.state = 2 // initialization done
- return
- }
-
var (
start int64
before tracestat
@@ -6572,9 +6569,14 @@ func doInit(t *initTask) {
before = inittrace
}
- firstFunc := add(unsafe.Pointer(t), (3+t.ndeps)*goarch.PtrSize)
- for i := uintptr(0); i < t.nfns; i++ {
- p := add(firstFunc, i*goarch.PtrSize)
+ if t.nfns == 0 {
+ // We should have pruned all of these in the linker.
+ throw("inittask with no functions")
+ }
+
+ firstFunc := add(unsafe.Pointer(t), 8)
+ for i := uint32(0); i < t.nfns; i++ {
+ p := add(firstFunc, uintptr(i)*goarch.PtrSize)
f := *(*func())(unsafe.Pointer(&p))
f()
}
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index e2533ae250..7bf96c31fc 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -446,6 +446,10 @@ type moduledata struct {
pluginpath string
pkghashes []modulehash
+ // This slice records the initializing tasks that need to be
+ // done to start up the program. It is built by the linker.
+ inittasks []*initTask
+
modulename string
modulehashes []modulehash