goのmainの始まる前(1)
- そう言えばgoのmainの始まる前をまじまじと折ったことはないなと
- 思ったのでちょっとだけ追う
runtime.main
から呼ばれているようだ
// The main goroutine. func main() {
getg()
が実行されてcurrentのg
が返される
g := getg()
type g struct { stack stack // offset known to runtime/cgo stackguard0 uintptr // offset known to liblink stackguard1 uintptr // offset known to liblink _panic *_panic // innermost panic - offset known to liblink _defer *_defer // innermost defer m *m // current m; offset known to arm liblink sched gobuf syscallsp uintptr // if status==Gsyscall, syscallsp = sched.sp to use during gc syscallpc uintptr // if status==Gsyscall, syscallpc = sched.pc to use during gc stktopsp uintptr // expected sp at top of stack, to check in traceback param unsafe.Pointer // passed parameter on wakeup atomicstatus uint32 stackLock uint32 // sigprof/scang lock; TODO: fold in to atomicstatus goid int64 schedlink guintptr waitsince int64 // approx time when the g become blocked waitreason waitReason // if status==Gwaiting preempt bool // preemption signal, duplicates stackguard0 = stackpreempt paniconfault bool // panic (instead of crash) on unexpected fault address preemptscan bool // preempted g does scan for gc gcscandone bool // g has scanned stack; protected by _Gscan bit in status gcscanvalid bool // false at start of gc cycle, true if G has not run since last scan; TODO: remove? throwsplit bool // must not split stack raceignore int8 // ignore race detection events sysblocktraced bool // StartTrace has emitted EvGoInSyscall about this goroutine sysexitticks int64 // cputicks when syscall has returned (for tracing) traceseq uint64 // trace event sequencer tracelastp puintptr // last P emitted an event for this goroutine lockedm muintptr sig uint32 writebuf []byte sigcode0 uintptr sigcode1 uintptr sigpc uintptr gopc uintptr // pc of go statement that created this goroutine ancestors *[]ancestorInfo // ancestor information goroutine(s) that created this goroutine (only used if debug.tracebackancestors) startpc uintptr // pc of goroutine function racectx uintptr waiting *sudog // sudog structures this g is waiting on (that have a valid elem ptr); in lock order cgoCtxt []uintptr // cgo traceback context labels unsafe.Pointer // profiler labels timer *timer // cached timer for time.Sleep selectDone uint32 // are we participating in a select and did someone win the race? gcAssistBytes int64 }
- max stack sizeを設定
- 64bitだと1Gで32bitだと250Mに設定
if sys.PtrSize == 8 { maxstacksize = 1000000000 } else { maxstacksize = 250000000 }
- メインゴルーチンをmain threadに固定する
lockOSThread()
//go:nosplit func lockOSThread() { getg().m.lockedInt++ dolockOSThread() }
- 現在のgへ
m.lockedg
とlockedm
へセット
func dolockOSThread() { if GOARCH == "wasm" { return // no threads on wasm yet } _g_ := getg() _g_.m.lockedg.set(_g_) _g_.lockedm.set(_g_.m) }
- runtimeの初期化
runtime_init() // must be before defer
- 中身どこだろうなこれ
//go:linkname runtime_init runtime.init func runtime_init()
- gcの初期化
bgsweep
をgoroutineで実行
func gcenable() { c := make(chan int, 1) go bgsweep(c) <-c memstats.enablegc = true // now that runtime is initialized, GC is okay }
- これがsweepの実体
func bgsweep(c chan int) { sweep.g = getg() lock(&sweep.lock) sweep.parked = true c <- 1 goparkunlock(&sweep.lock, waitReasonGCSweepWait, traceEvGoBlock, 1) for { for sweepone() != ^uintptr(0) { sweep.nbgsweep++ Gosched() } for freeSomeWbufs(true) { Gosched() } lock(&sweep.lock) if !isSweepDone() { // This can happen if a GC runs between // gosweepone returning ^0 above // and the lock being acquired. unlock(&sweep.lock) continue } sweep.parked = true goparkunlock(&sweep.lock, waitReasonGCSweepWait, traceEvGoBlock, 1) } }
- で、やっとmainを呼んでいる箇所がきた
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)
とりあえず、今日はこのぐらいにする。 気が向いたら続き