// Create a new g in state _Grunnable (or _Gwaiting if parked is true), starting at fn. // callerpc is the address of the go statement that created this. The caller is responsible // for adding the new g to the scheduler. If parked is true, waitreason must be non-zero. func newproc1(fn *funcval, callergp *g, callerpc uintptr, parked bool, waitreason waitReason) *g { if fn == nil { fatal("go of nil func value") }
mp := acquirem() // disable preemption because we hold M and P in local vars. pp := mp.p.ptr()
// 尝试复用dead状态协程,从空闲列表中获取 newg := gfget(pp) if newg == nil { // 如果没有可以复用的,申请一个新的协程,并从堆中申请一块内存,初始化他的栈 newg = malg(stackMin) // 暂时设置成消亡态去禁止gc扫描 casgstatus(newg, _Gidle, _Gdead) allgadd(newg) // publishes with a g->status of Gdead so GC scanner doesn't look at uninitialized stack. } if newg.stack.hi == 0 { throw("newproc1: newg missing stack") }
if readgstatus(newg) != _Gdead { throw("newproc1: new g is not Gdead") }
totalSize := uintptr(4*goarch.PtrSize + sys.MinFrameSize) // extra space in case of reads slightly beyond frame // 栈对齐 totalSize = alignUp(totalSize, sys.StackAlign) sp := newg.stack.hi - totalSize if usesLR { // caller's LR *(*uintptr)(unsafe.Pointer(sp)) = 0 prepGoExitFrame(sp) }
// 清除内存 memclrNoHeapPointers(unsafe.Pointer(&newg.sched), unsafe.Sizeof(newg.sched))
// 设置调度相关字段 newg.sched.sp = sp newg.stktopsp = sp // 确保协程执行结束后,跳转到goexit newg.sched.pc = abi.FuncPCABI0(goexit) + sys.PCQuantum // +PCQuantum so that previous instruction is in same function newg.sched.g = guintptr(unsafe.Pointer(newg)) gostartcallfn(&newg.sched, fn) newg.parentGoid = callergp.goid newg.gopc = callerpc newg.ancestors = saveAncestors(callergp)
// 设置入口函数 newg.startpc = fn.fn
// 如果是系统Goroutine if isSystemGoroutine(newg, false) { sched.ngsys.Add(1) } else { // 对用户栈执行profile相关处理 if mp.curg != nil { newg.labels = mp.curg.labels } if goroutineProfile.active { // A concurrent goroutine profile is running. It should include // exactly the set of goroutines that were alive when the goroutine // profiler first stopped the world. That does not include newg, so // mark it as not needing a profile before transitioning it from // _Gdead. newg.goroutineProfiled.Store(goroutineProfileSatisfied) } }
// 将一个栈添加到垃圾回收器的扫描任务中 gcController.addScannableStack(pp, int64(newg.stack.hi-newg.stack.lo))
// 修改协程状态为运行态 var status uint32 = _Grunnable casgstatus(newg, _Gdead, status)
if pp.goidcache == pp.goidcacheend { // Sched.goidgen is the last allocated id, // this batch must be [sched.goidgen+1, sched.goidgen+GoidCacheBatch]. // At startup sched.goidgen=0, so main goroutine receives goid=1. pp.goidcache = sched.goidgen.Add(_GoidCacheBatch) pp.goidcache -= _GoidCacheBatch - 1 pp.goidcacheend = pp.goidcache + _GoidCacheBatch } newg.goid = pp.goidcache pp.goidcache++ newg.trace.reset() ... releasem(mp)
return newg }
|