go version go1.12.5 darwin/amd64

14章Go启动疏导

// The bootstrap sequence is://// call osinit// call schedinit// make & queue new G// call runtime·mstart//// The new G calls runtime·main.
TEXT runtime·rt0_go(SB),NOSPLIT,$0---略---CALL runtime·args(SB)CALL runtime·osinit(SB)CALL runtime·schedinit(SB)// create a new goroutine to start programMOVQ $runtime·mainPC(SB), AX       // entry     (runtime·mainPC+0(SB)/8,$runtime·main(SB))PUSHQ AXPUSHQ $0 // arg sizeCALL runtime·newproc(SB)POPQ AXPOPQ AX// start this MCALL runtime·mstart(SB)CALL runtime·abort(SB)  // mstart should never returnRET

osinit

func osinit() {   // pthread_create delayed until end of goenvs so that we can look at the environment first.   ncpu = getncpu()   physPageSize = getPageSize()}
func schedinit() {   // raceinit must be the first call to race detector.   // In particular, it must be done before mallocinit below calls racemapshadow.   _g_ := getg()   if raceenabled {      _g_.racectx, raceprocctx0 = raceinit()   }   // 最大零碎线程数(非goroutines数)   sched.maxmcount = 10000   // 栈、内存、调度器初始化   tracebackinit()   moduledataverify()   stackinit()   mallocinit()   mcommoninit(_g_.m)      // 初始化CPU等   cpuinit()       // must run before alginit   alginit()       // maps must not be used before this call   modulesinit()   // provides activeModules   typelinksinit() // uses maps, activeModules   itabsinit()     // uses activeModules   msigsave(_g_.m)   initSigmask = _g_.m.sigmask   goargs()   goenvs()      // 初始化调试相干   parsedebugvars()      // GC   gcinit()      sched.lastpoll = uint64(nanotime())   procs := ncpu   if n, ok := atoi32(gogetenv("GOMAXPROCS")); ok && n > 0 {      procs = n   }   if procresize(procs) != nil {      throw("unknown runnable goroutine during bootstrap")   }   // For cgocheck > 1, we turn on the write barrier at all times   // and check all pointer writes. We can't do this until after // procresize because the write barrier needs a P. if debug.cgocheck > 1 {   writeBarrier.cgo = true   writeBarrier.enabled = true   for _, p := range allp {         p.wbBuf.reset()      }   }   if buildVersion == "" {      // Condition should never trigger. This code just serves      // to ensure runtime·buildVersion is kept in the resulting binary.       buildVersion = "unknown"   }}

runtime.main

// The main goroutine.func main() {   g := getg()   // Racectx of m0->g0 is used only as the parent of the main goroutine. // It must not be used for anything else. g.m.g0.racectx = 0 // Max stack size is 1 GB on 64-bit, 250 MB on 32-bit. // Using decimal instead of binary GB and MB because // they look nicer in the stack overflow failure message. if sys.PtrSize == 8 {      maxstacksize = 1000000000 } else {      maxstacksize = 250000000 }   // Allow newproc to start new Ms. mainStarted = true if GOARCH != "wasm" { // no threads on wasm yet, so no sysmon systemstack(func() {         newm(sysmon, nil)      })   }   // Lock the main goroutine onto this, the main OS thread, // during initialization. Most programs won't care, but a few // do require certain calls to be made by the main thread. // Those can arrange for main.main to run in the main thread // by calling runtime.LockOSThread during initialization // to preserve the lock. lockOSThread()   if g.m != &m0 {      throw("runtime.main not on m0")   }   runtime_init() // must be before defer if nanotime() == 0 {      throw("nanotime returning zero")   }   // Defer unlock so that runtime.Goexit during init does the unlock too. needUnlock := true defer func() {      if needUnlock {         unlockOSThread()      }   }()   // Record when the world started. runtimeInitTime = nanotime()   gcenable()   main_init_done = make(chan bool)   if iscgo {      if _cgo_thread_start == nil {         throw("_cgo_thread_start missing")      }      if GOOS != "windows" {         if _cgo_setenv == nil {            throw("_cgo_setenv missing")         }         if _cgo_unsetenv == nil {            throw("_cgo_unsetenv missing")         }      }      if _cgo_notify_runtime_init_done == nil {         throw("_cgo_notify_runtime_init_done missing")      }      // Start the template thread in case we enter Go from // a C-created thread and need to create a new thread. startTemplateThread()      cgocall(_cgo_notify_runtime_init_done, nil)   }   fn := main_init // make an indirect call, as the linker doesn't know the address of the main package when laying down the runtime fn()   close(main_init_done)   needUnlock = false unlockOSThread()   if isarchive || islibrary {      // A program compiled with -buildmode=c-archive or c-shared // has a main, but it is not executed. return }   fn = main_main // make an indirect call, as the linker doesn't know the address of the main package when laying down the runtime fn()   if raceenabled {      racefini()   }   // Make racy client program work: if panicking on // another goroutine at the same time as main returns, // let the other goroutine finish printing the panic trace. // Once it does, it will exit. See issues 3934 and 20018. if atomic.Load(&runningPanicDefers) != 0 {      // Running deferred functions should not take long. for c := 0; c < 1000; c++ {         if atomic.Load(&runningPanicDefers) == 0 {            break }         Gosched()      }   }   if atomic.Load(&panicking) != 0 {      gopark(nil, nil, waitReasonPanicWait, traceEvGoStop, 1)   }   exit(0)   for {      var x *int32 *x = 0 }}