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 program
MOVQ $runtime·mainPC(SB), AX       // entry     (runtime·mainPC+0(SB)/8,$runtime·main(SB))
PUSHQ AX
PUSHQ $0 // arg size
CALL runtime·newproc(SB)
POPQ AX
POPQ AX
// start this M
CALL runtime·mstart(SB)
CALL runtime·abort(SB)  // mstart should never return
RET

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
 }
}

xxx小M
30 声望11 粉丝

暂时放一些读书笔记, 很多内容没有整理好