上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
4.2.2 STW
STW 面向全局设置停止状态,让所有 P 停止任务执行。
// proc.go // stopTheWorld stops all P's from executing goroutines, interrupting // all goroutines at GC safe points and records reason as the reason // for the stop. On return, only the current goroutine's P is running. func stopTheWorld(reason string) { semacquire(&worldsema) stopTheWorldWithSema() }
func stopTheWorldWithSema() { _g_ := getg() lock(&sched.lock) // 停止计数器。(停止成功 -1) sched.stopwait = gomaxprocs // 会被 schedule 看到,引发 gcstopm 调用。 atomic.Store(&sched.gcwaiting, 1) // 向所有运行中的 G 发出抢占信号。 preemptall() // 停止当前 P,并调整。 _g_.m.p.ptr().status = _Pgcstop // Pgcstop is only diagnostic. sched.stopwait-- // 停止 Psyscall 状态的 P。 for _, p := range allp { s := p.status if s == _Psyscall && atomic.Cas(&p.status, s, _Pgcstop) { p.syscalltick++ sched.stopwait-- } } // 停止闲置 P。 for { p := pidleget() if p == nil { break } p.status = _Pgcstop sched.stopwait-- } wait := sched.stopwait > 0 unlock(&sched.lock) // 等待所有 P 停止。 if wait { for { // wait for 100us, then try to re-preempt in case of any races if notetsleep(&sched.stopnote, 100*1000) { noteclear(&sched.stopnote) break } preemptall() } } worldStopped() }
以上操作,会被 P schedule 观察到。
func schedule() { _g_ := getg() top: pp := _g_.m.p.ptr() pp.preempt = false if sched.gcwaiting != 0 { gcstopm() goto top } ... execute(gp, inheritTime) }
// Stops the current m for stopTheWorld. // Returns when the world is restarted. func gcstopm() { _p_ := releasep() _p_.status = _Pgcstop sched.stopwait-- // 如果是最后一个待停止 P,则终止 stopTheWorldWithSema 里的 wait 循环。 if sched.stopwait == 0 { notewakeup(&sched.stopnote) } stopm() }
非但如此,连后台监控 sysmon 也会被停止。
func sysmon() { for { usleep(delay) now := nanotime() if debug.schedtrace <= 0 && (sched.gcwaiting != 0 || atomic.Load(&sched.npidle) == uint32(gomaxprocs)) { if atomic.Load(&sched.gcwaiting) != 0 || atomic.Load(&sched.npidle) == uint32(gomaxprocs) { next, _ := timeSleepUntil() if next > now { atomic.Store(&sched.sysmonwait, 1) syscallWake = notetsleep(&sched.sysmonnote, sleep) atomic.Store(&sched.sysmonwait, 0) noteclear(&sched.sysmonnote) } } } ... } }
重启
与之相对的是重启 P 任务。
func startTheWorldWithSema(emitTraceEvent bool) int64 { assertWorldStopped() // 重置 allP,返回有任务的 P 链表。 procs := gomaxprocs p1 := procresize(procs) // 解除状态。 sched.gcwaiting = 0 // 唤醒 sysmon。 if sched.sysmonwait != 0 { sched.sysmonwait = 0 notewakeup(&sched.sysmonnote) } worldStarted() // 唤醒有任务的 P。 for p1 != nil { p := p1 p1 = p1.link.ptr() if p.m != 0 { mp := p.m.ptr() p.m = 0 mp.nextp.set(p) notewakeup(&mp.park) } else { // Start M to run P. Do not start another M below. newm(nil, p, -1) } } // Wakeup an additional proc in case we have excessive runnable goroutines // in local queues or in the global queue. If we don't, the proc will park itself. // If we have lots of excessive work, resetspinning will unpark additional procs as necessary. wakep() return startTime }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论