// The C call to Go came from a thread not currently running
// any Go. In the case of -buildmode=c-archive or c-shared,
// this call may be coming in before package initialization
- // is complete. Wait until it is.
- <-main_init_done
+ // is complete. Don't proceed until it is.
+ //
+ // We check a bool first for speed, and wait on a channel
+ // if it's not ready.
+ if !mainInitDone.Load() {
+ <-mainInitDoneChan
+ }
}
// Check whether the profiler needs to be turned on or off; this route to
// 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,
-// so all cgo calls can rely on it existing. When main_init is complete,
-// it is closed, meaning cgocallbackg can reliably receive from it.
-var main_init_done chan bool
+// mainInitDone is a signal used by cgocallbackg that initialization
+// has been completed. If this is false, wait on mainInitDoneChan.
+var mainInitDone atomic.Bool
+
+// mainInitDoneChan is closed after initialization has been completed.
+// It is made before _cgo_notify_runtime_init_done, so all cgo
+// calls can rely on it existing.
+var mainInitDoneChan chan bool
//go:linkname main_main main.main
func main_main()
gcenable()
defaultGOMAXPROCSUpdateEnable() // don't STW before runtime initialized.
- main_init_done = make(chan bool)
+ mainInitDoneChan = make(chan bool)
if iscgo {
if _cgo_pthread_key_created == nil {
throw("_cgo_pthread_key_created missing")
// of collecting statistics in malloc and newproc
inittrace.active = false
- close(main_init_done)
+ mainInitDone.Store(true)
+ close(mainInitDoneChan)
needUnlock = false
unlockOSThread()