// The main goroutine. funcmain() { ........... if GOARCH != "wasm" { // no threads on wasm yet, so no sysmon // For runtime_syscall_doAllThreadsSyscall, we // register sysmon is not ready for the world to be // stopped. atomic.Store(&sched.sysmonStarting, 1) systemstack(func() { newm(sysmon, nil, -1) }) } ............ 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()
注意哦,这个 main 不是我们写的 main,而是 runtime 的 main,go 启动的时候会调用这个 runtime.main ,而我们的写的 main 会在后面被调用,也就是 main.main 的时候被调用。而 newm 方法会创建一个 m,这里的 m 就是 gpm 模型中的 m,newm 调用 newm1 然后调用 mstart 启动
lock(&sched.sysmonlock) // Update now in case we blocked on sysmonnote or spent a long time // blocked on schedlock or sysmonlock above. now = nanotime()
// trigger libc interceptors if needed if *cgo_yield != nil { asmcgocall(*cgo_yield, nil) } // poll network if not polled for more than 10ms lastpoll := int64(atomic.Load64(&sched.lastpoll)) if netpollinited() && lastpoll != 0 && lastpoll+10*1000*1000 < now { atomic.Cas64(&sched.lastpoll, uint64(lastpoll), uint64(now)) list := netpoll(0) // non-blocking - returns list of goroutines if !list.empty() { // Need to decrement number of idle locked M's // (pretending that one more is running) before injectglist. // Otherwise it can lead to the following situation: // injectglist grabs all P's but before it starts M's to run the P's, // another M returns from syscall, finishes running its G, // observes that there is no work to do and no other running M's // and reports deadlock. incidlelocked(-1) injectglist(&list) incidlelocked(1) } } mDoFixup()
// retake P's blocked in syscalls // and preempt long running G's if retake(now) != 0 { idle = 0 } else { idle++ }
retake 方法相信你应该不会陌生,这个方法处理了抢占的情况:一种是阻塞在了系统调用上的 P ,一种是运行时间过长的 G。这个时候就需要解绑 P 和 M,让其他的线程能获得 P 来继续执行其他的 G。具体里面的抢占的工作,让我们留到抢占的章节里面去,这里就不再赘述了。
gc 工作
1 2 3 4 5 6 7 8 9
// check if we need to force a GC if t := (gcTrigger{kind: gcTriggerTime, now: now}); t.test() && atomic.Load(&forcegc.idle) != 0 { lock(&forcegc.lock) forcegc.idle = 0 var list gList list.push(forcegc.g) injectglist(&list) unlock(&forcegc.lock) }
创建 gcTrigger 并调用 test 方法来确定是否需要 gc 如果需要的话就将执行 gc 的 g 直接 push 到全局队列中,然后调度执行
总结
sysmon 不需要 P 只需要 M 即可执行,能休息就休息,没工作时就慢下来,sysmon 主要做了以下几样工作: