src/runtime/proc.go GO 8,178 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 8,178.
1// Copyright 2014 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45package runtime67import (8	"internal/abi"9	"internal/cpu"10	"internal/goarch"11	"internal/goexperiment"12	"internal/goos"13	"internal/runtime/atomic"14	"internal/runtime/exithook"15	"internal/runtime/maps"16	"internal/runtime/sys"17	"internal/strconv"18	"internal/stringslite"19	"unsafe"20)2122// set using cmd/go/internal/modload.ModInfoProg23var modinfo string2425// Goroutine scheduler26// The scheduler's job is to distribute ready-to-run goroutines over worker threads.27//28// The main concepts are:29// G - goroutine.30// M - worker thread, or machine.31// P - processor, a resource that is required to execute Go code.32//     M must have an associated P to execute Go code, however it can be33//     blocked or in a syscall w/o an associated P.34//35// Design doc at https://golang.org/s/go11sched.3637// Worker thread parking/unparking.38// We need to balance between keeping enough running worker threads to utilize39// available hardware parallelism and parking excessive running worker threads40// to conserve CPU resources and power. This is not simple for two reasons:41// (1) scheduler state is intentionally distributed (in particular, per-P work42// queues), so it is not possible to compute global predicates on fast paths;43// (2) for optimal thread management we would need to know the future (don't park44// a worker thread when a new goroutine will be readied in near future).45//46// Three rejected approaches that would work badly:47// 1. Centralize all scheduler state (would inhibit scalability).48// 2. Direct goroutine handoff. That is, when we ready a new goroutine and there49//    is a spare P, unpark a thread and handoff it the thread and the goroutine.50//    This would lead to thread state thrashing, as the thread that readied the51//    goroutine can be out of work the very next moment, we will need to park it.52//    Also, it would destroy locality of computation as we want to preserve53//    dependent goroutines on the same thread; and introduce additional latency.54// 3. Unpark an additional thread whenever we ready a goroutine and there is an55//    idle P, but don't do handoff. This would lead to excessive thread parking/56//    unparking as the additional threads will instantly park without discovering57//    any work to do.58//59// The current approach:60//61// This approach applies to three primary sources of potential work: readying a62// goroutine, new/modified-earlier timers, and idle-priority GC. See below for63// additional details.64//65// We unpark an additional thread when we submit work if (this is wakep()):66// 1. There is an idle P, and67// 2. There are no "spinning" worker threads.68//69// A worker thread is considered spinning if it is out of local work and did70// not find work in the global run queue or netpoller; the spinning state is71// denoted in m.spinning and in sched.nmspinning. Threads unparked this way are72// also considered spinning; we don't do goroutine handoff so such threads are73// out of work initially. Spinning threads spin on looking for work in per-P74// run queues and timer heaps or from the GC before parking. If a spinning75// thread finds work it takes itself out of the spinning state and proceeds to76// execution. If it does not find work it takes itself out of the spinning77// state and then parks.78//79// If there is at least one spinning thread (sched.nmspinning>1), we don't80// unpark new threads when submitting work. To compensate for that, if the last81// spinning thread finds work and stops spinning, it must unpark a new spinning82// thread. This approach smooths out unjustified spikes of thread unparking,83// but at the same time guarantees eventual maximal CPU parallelism84// utilization.85//86// The main implementation complication is that we need to be very careful87// during spinning->non-spinning thread transition. This transition can race88// with submission of new work, and either one part or another needs to unpark89// another worker thread. If they both fail to do that, we can end up with90// semi-persistent CPU underutilization.91//92// The general pattern for submission is:93// 1. Submit work to the local or global run queue, timer heap, or GC state.94// 2. #StoreLoad-style memory barrier.95// 3. Check sched.nmspinning.96//97// The general pattern for spinning->non-spinning transition is:98// 1. Decrement nmspinning.99// 2. #StoreLoad-style memory barrier.100// 3. Check all per-P work queues and GC for new work.101//102// Note that all this complexity does not apply to global run queue as we are103// not sloppy about thread unparking when submitting to global queue. Also see104// comments for nmspinning manipulation.105//106// How these different sources of work behave varies, though it doesn't affect107// the synchronization approach:108// * Ready goroutine: this is an obvious source of work; the goroutine is109//   immediately ready and must run on some thread eventually.110// * New/modified-earlier timer: The current timer implementation (see time.go)111//   uses netpoll in a thread with no work available to wait for the soonest112//   timer. If there is no thread waiting, we want a new spinning thread to go113//   wait.114// * Idle-priority GC: The GC wakes a stopped idle thread to contribute to115//   background GC work (note: currently disabled per golang.org/issue/19112).116//   Also see golang.org/issue/44313, as this should be extended to all GC117//   workers.118119var (120	m0           m121	g0           g122	mcache0      *mcache123	raceprocctx0 uintptr124	raceFiniLock mutex125)126127// This slice records the initializing tasks that need to be128// done to start up the runtime. It is built by the linker.129var runtime_inittasks []*initTask130131// mainInitDone is a signal used by cgocallbackg that initialization132// has been completed. If this is false, wait on mainInitDoneChan.133var mainInitDone atomic.Bool134135// mainInitDoneChan is closed after initialization has been completed.136// It is made before _cgo_notify_runtime_init_done, so all cgo137// calls can rely on it existing.138var mainInitDoneChan chan bool139140//go:linkname main_main main.main141func main_main()142143// mainStarted indicates that the main M has started.144var mainStarted bool145146// runtimeInitTime is the nanotime() at which the runtime started.147var runtimeInitTime int64148149// Value to use for signal mask for newly created M's.150var initSigmask sigset151152// The main goroutine.153func main() {154	mp := getg().m155156	// Racectx of m0->g0 is used only as the parent of the main goroutine.157	// It must not be used for anything else.158	mp.g0.racectx = 0159160	// Max stack size is 1 GB on 64-bit, 250 MB on 32-bit.161	// Using decimal instead of binary GB and MB because162	// they look nicer in the stack overflow failure message.163	if goarch.PtrSize == 8 {164		maxstacksize = 1000000000165	} else {166		maxstacksize = 250000000167	}168169	// An upper limit for max stack size. Used to avoid random crashes170	// after calling SetMaxStack and trying to allocate a stack that is too big,171	// since stackalloc works with 32-bit sizes.172	maxstackceiling = 2 * maxstacksize173174	// Allow newproc to start new Ms.175	mainStarted = true176177	if haveSysmon {178		systemstack(func() {179			newm(sysmon, nil, -1)180		})181	}182183	// Lock the main goroutine onto this, the main OS thread,184	// during initialization. Most programs won't care, but a few185	// do require certain calls to be made by the main thread.186	// Those can arrange for main.main to run in the main thread187	// by calling runtime.LockOSThread during initialization188	// to preserve the lock.189	lockOSThread()190191	if mp != &m0 {192		throw("runtime.main not on m0")193	}194195	// Record when the world started.196	// Must be before doInit for tracing init.197	runtimeInitTime = nanotime()198	if runtimeInitTime == 0 {199		throw("nanotime returning zero")200	}201202	if debug.inittrace != 0 {203		inittrace.id = getg().goid204		inittrace.active = true205	}206207	doInit(runtime_inittasks) // Must be before defer.208209	// Defer unlock so that runtime.Goexit during init does the unlock too.210	needUnlock := true211	defer func() {212		if needUnlock {213			unlockOSThread()214		}215	}()216217	gcenable()218	defaultGOMAXPROCSUpdateEnable() // don't STW before runtime initialized.219220	// If we encountered a removed GODEBUG during startup we can panic now.221	if k := invalidGODEBUG.key; k != "" {222		v := invalidGODEBUG.value223		r := strconv.Itoa(invalidGODEBUG.removed)224		fatal(`removed GODEBUG "` + k + `" set to old value "` + v + `" in environment (https://go.dev/doc/godebug#go-1` + r + `)`)225	}226227	mainInitDoneChan = make(chan bool)228	if iscgo {229		if _cgo_pthread_key_created == nil {230			throw("_cgo_pthread_key_created missing")231		}232233		if GOOS != "windows" {234			if _cgo_thread_start == nil {235				throw("_cgo_thread_start missing")236			}237			if _cgo_setenv == nil {238				throw("_cgo_setenv missing")239			}240			if _cgo_unsetenv == nil {241				throw("_cgo_unsetenv missing")242			}243		}244		if _cgo_notify_runtime_init_done == nil {245			throw("_cgo_notify_runtime_init_done missing")246		}247248		// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.249		if set_crosscall2 == nil {250			throw("set_crosscall2 missing")251		}252		set_crosscall2()253254		// Start the template thread in case we enter Go from255		// a C-created thread and need to create a new thread.256		startTemplateThread()257		cgocall(_cgo_notify_runtime_init_done, nil)258	}259260	// Run the initializing tasks. Depending on build mode this261	// list can arrive a few different ways, but it will always262	// contain the init tasks computed by the linker for all the263	// packages in the program (excluding those added at runtime264	// by package plugin). Run through the modules in dependency265	// order (the order they are initialized by the dynamic266	// loader, i.e. they are added to the moduledata linked list).267	last := lastmoduledatap // grab before loop starts. Any added modules after this point will do their own doInit calls.268	for m := &firstmoduledata; true; m = m.next {269		doInit(m.inittasks)270		if m == last {271			break272		}273	}274275	// Disable init tracing after main init done to avoid overhead276	// of collecting statistics in malloc and newproc277	inittrace.active = false278279	mainInitDone.Store(true)280	close(mainInitDoneChan)281282	needUnlock = false283	unlockOSThread()284285	if isarchive || islibrary {286		// A program compiled with -buildmode=c-archive or c-shared287		// has a main, but it is not executed.288		if GOARCH == "wasm" {289			// On Wasm, pause makes it return to the host.290			// Unlike cgo callbacks where Ms are created on demand,291			// on Wasm we have only one M. So we keep this M (and this292			// G) for callbacks.293			// Using the caller's SP unwinds this frame and backs to294			// goexit. The -16 is: 8 for goexit's (fake) return PC,295			// and pause's epilogue pops 8.296			pause(sys.GetCallerSP() - 16) // should not return297			panic("unreachable")298		}299		return300	}301	fn := main_main // make an indirect call, as the linker doesn't know the address of the main package when laying down the runtime302	fn()303304	// Check for C memory leaks if using ASAN and we've made cgo calls,305	// or if we are running as a library in a C program.306	// We always make one cgo call, above, to notify_runtime_init_done,307	// so we ignore that one.308	// No point in leak checking if no cgo calls, since leak checking309	// just looks for objects allocated using malloc and friends.310	// Just checking iscgo doesn't help because asan implies iscgo.311	exitHooksRun := false312	if asanenabled && (isarchive || islibrary || NumCgoCall() > 1) {313		runExitHooks(0) // lsandoleakcheck may not return314		exitHooksRun = true315		lsandoleakcheck()316	}317318	// Make racy client program work: if panicking on319	// another goroutine at the same time as main returns,320	// let the other goroutine finish printing the panic trace.321	// Once it does, it will exit. See issues 3934 and 20018.322	if runningPanicDefers.Load() != 0 {323		// Running deferred functions should not take long.324		for c := 0; c < 1000; c++ {325			if runningPanicDefers.Load() == 0 {326				break327			}328			Gosched()329		}330	}331	if panicking.Load() != 0 {332		gopark(nil, nil, waitReasonPanicWait, traceBlockForever, 1)333	}334	if !exitHooksRun {335		runExitHooks(0)336	}337	if raceenabled {338		racefini() // does not return339	}340341	exit(0)342	for {343		var x *int32344		*x = 0345	}346}347348// os_beforeExit is called from os.Exit(0).349//350//go:linkname os_beforeExit os.runtime_beforeExit351func os_beforeExit(exitCode int) {352	runExitHooks(exitCode)353	if exitCode == 0 && raceenabled {354		racefini()355	}356357	// See comment in main, above.358	if exitCode == 0 && asanenabled && (isarchive || islibrary || NumCgoCall() > 1) {359		lsandoleakcheck()360	}361}362363func init() {364	exithook.Gosched = Gosched365	exithook.Goid = func() uint64 { return getg().goid }366	exithook.Throw = throw367}368369func runExitHooks(code int) {370	exithook.Run(code)371}372373// start forcegc helper goroutine374func init() {375	go forcegchelper()376}377378func forcegchelper() {379	forcegc.g = getg()380	lockInit(&forcegc.lock, lockRankForcegc)381	for {382		lock(&forcegc.lock)383		if forcegc.idle.Load() {384			throw("forcegc: phase error")385		}386		forcegc.idle.Store(true)387		goparkunlock(&forcegc.lock, waitReasonForceGCIdle, traceBlockSystemGoroutine, 1)388		// this goroutine is explicitly resumed by sysmon389		if debug.gctrace > 0 {390			println("GC forced")391		}392		// Time-triggered, fully concurrent.393		gcStart(gcTrigger{kind: gcTriggerTime, now: nanotime()})394	}395}396397// Gosched yields the processor, allowing other goroutines to run. It does not398// suspend the current goroutine, so execution resumes automatically.399//400//go:nosplit401func Gosched() {402	checkTimeouts()403	mcall(gosched_m)404}405406// goschedguarded yields the processor like gosched, but also checks407// for forbidden states and opts out of the yield in those cases.408//409//go:nosplit410func goschedguarded() {411	mcall(goschedguarded_m)412}413414// goschedIfBusy yields the processor like gosched, but only does so if415// there are no idle Ps or if we're on the only P and there's nothing in416// the run queue. In both cases, there is freely available idle time.417//418//go:nosplit419func goschedIfBusy() {420	gp := getg()421	// Call gosched if gp.preempt is set; we may be in a tight loop that422	// doesn't otherwise yield.423	if !gp.preempt && sched.npidle.Load() > 0 {424		return425	}426	mcall(gosched_m)427}428429// Puts the current goroutine into a waiting state and calls unlockf on the430// system stack.431//432// If unlockf returns false, the goroutine is resumed.433//434// unlockf must not access this G's stack, as it may be moved between435// the call to gopark and the call to unlockf.436//437// Note that because unlockf is called after putting the G into a waiting438// state, the G may have already been readied by the time unlockf is called439// unless there is external synchronization preventing the G from being440// readied. If unlockf returns false, it must guarantee that the G cannot be441// externally readied.442//443// Reason explains why the goroutine has been parked. It is displayed in stack444// traces and heap dumps. Reasons should be unique and descriptive. Do not445// re-use reasons, add new ones.446//447// gopark should be an internal detail,448// but widely used packages access it using linkname.449// Notable members of the hall of shame include:450//   - gvisor.dev/gvisor451//   - github.com/sagernet/gvisor452//453// Do not remove or change the type signature.454// See go.dev/issue/67401.455//456//go:linkname gopark457func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason waitReason, traceReason traceBlockReason, traceskip int) {458	if reason != waitReasonSleep {459		checkTimeouts() // timeouts may expire while two goroutines keep the scheduler busy460	}461	mp := acquirem()462	gp := mp.curg463	status := readgstatus(gp)464	if status != _Grunning && status != _Gscanrunning {465		throw("gopark: bad g status")466	}467	mp.waitlock = lock468	mp.waitunlockf = unlockf469	gp.waitreason = reason470	mp.waitTraceBlockReason = traceReason471	mp.waitTraceSkip = traceskip472	releasem(mp)473	// can't do anything that might move the G between Ms here.474	mcall(park_m)475}476477// Puts the current goroutine into a waiting state and unlocks the lock.478// The goroutine can be made runnable again by calling goready(gp).479func goparkunlock(lock *mutex, reason waitReason, traceReason traceBlockReason, traceskip int) {480	gopark(parkunlock_c, unsafe.Pointer(lock), reason, traceReason, traceskip)481}482483// goready should be an internal detail,484// but widely used packages access it using linkname.485// Notable members of the hall of shame include:486//   - gvisor.dev/gvisor487//   - github.com/sagernet/gvisor488//489// Do not remove or change the type signature.490// See go.dev/issue/67401.491//492//go:linkname goready493func goready(gp *g, traceskip int) {494	systemstack(func() {495		ready(gp, traceskip, true)496	})497}498499//go:nosplit500func acquireSudog() *sudog {501	// Delicate dance: the semaphore implementation calls502	// acquireSudog, acquireSudog calls new(sudog),503	// new calls malloc, malloc can call the garbage collector,504	// and the garbage collector calls the semaphore implementation505	// in stopTheWorld.506	// Break the cycle by doing acquirem/releasem around new(sudog).507	// The acquirem/releasem increments m.locks during new(sudog),508	// which keeps the garbage collector from being invoked.509	mp := acquirem()510	pp := mp.p.ptr()511	if len(pp.sudogcache) == 0 {512		lock(&sched.sudoglock)513		// First, try to grab a batch from central cache.514		for len(pp.sudogcache) < cap(pp.sudogcache)/2 && sched.sudogcache != nil {515			s := sched.sudogcache516			sched.sudogcache = s.next517			s.next = nil518			pp.sudogcache = append(pp.sudogcache, s)519		}520		unlock(&sched.sudoglock)521		// If the central cache is empty, allocate a new one.522		if len(pp.sudogcache) == 0 {523			pp.sudogcache = append(pp.sudogcache, new(sudog))524		}525	}526	n := len(pp.sudogcache)527	s := pp.sudogcache[n-1]528	pp.sudogcache[n-1] = nil529	pp.sudogcache = pp.sudogcache[:n-1]530	if s.elem.get() != nil {531		throw("acquireSudog: found s.elem != nil in cache")532	}533	releasem(mp)534	return s535}536537//go:nosplit538func releaseSudog(s *sudog) {539	if s.elem.get() != nil {540		throw("runtime: sudog with non-nil elem")541	}542	if s.isSelect {543		throw("runtime: sudog with non-false isSelect")544	}545	if s.next != nil {546		throw("runtime: sudog with non-nil next")547	}548	if s.prev != nil {549		throw("runtime: sudog with non-nil prev")550	}551	if s.waitlink != nil {552		throw("runtime: sudog with non-nil waitlink")553	}554	if s.c.get() != nil {555		throw("runtime: sudog with non-nil c")556	}557	gp := getg()558	if gp.param != nil {559		throw("runtime: releaseSudog with non-nil gp.param")560	}561	mp := acquirem() // avoid rescheduling to another P562	pp := mp.p.ptr()563	if len(pp.sudogcache) == cap(pp.sudogcache) {564		// Transfer half of local cache to the central cache.565		var first, last *sudog566		for len(pp.sudogcache) > cap(pp.sudogcache)/2 {567			n := len(pp.sudogcache)568			p := pp.sudogcache[n-1]569			pp.sudogcache[n-1] = nil570			pp.sudogcache = pp.sudogcache[:n-1]571			if first == nil {572				first = p573			} else {574				last.next = p575			}576			last = p577		}578		lock(&sched.sudoglock)579		last.next = sched.sudogcache580		sched.sudogcache = first581		unlock(&sched.sudoglock)582	}583	pp.sudogcache = append(pp.sudogcache, s)584	releasem(mp)585}586587// called from assembly.588func badmcall(fn func(*g)) {589	throw("runtime: mcall called on m->g0 stack")590}591592func badmcall2(fn func(*g)) {593	throw("runtime: mcall function returned")594}595596func badreflectcall() {597	panic(plainError("arg size to reflect.call more than 1GB"))598}599600//go:nosplit601//go:nowritebarrierrec602func badmorestackg0() {603	if !crashStackImplemented {604		writeErrStr("fatal: morestack on g0\n")605		return606	}607608	g := getg()609	switchToCrashStack(func() {610		print("runtime: morestack on g0, stack [", hex(g.stack.lo), " ", hex(g.stack.hi), "], sp=", hex(g.sched.sp), ", called from\n")611		g.m.traceback = 2 // include pc and sp in stack trace612		traceback1(g.sched.pc, g.sched.sp, g.sched.lr, g, 0)613		print("\n")614615		throw("morestack on g0")616	})617}618619//go:nosplit620//go:nowritebarrierrec621func badmorestackgsignal() {622	writeErrStr("fatal: morestack on gsignal\n")623}624625//go:nosplit626func badctxt() {627	throw("ctxt != 0")628}629630// gcrash is a fake g that can be used when crashing due to bad631// stack conditions.632var gcrash g633634var crashingG atomic.Pointer[g]635636// Switch to crashstack and call fn, with special handling of637// concurrent and recursive cases.638//639// Nosplit as it is called in a bad stack condition (we know640// morestack would fail).641//642//go:nosplit643//go:nowritebarrierrec644func switchToCrashStack(fn func()) {645	me := getg()646	if crashingG.CompareAndSwapNoWB(nil, me) {647		switchToCrashStack0(fn) // should never return648		abort()649	}650	if crashingG.Load() == me {651		// recursive crashing. too bad.652		writeErrStr("fatal: recursive switchToCrashStack\n")653		abort()654	}655	// Another g is crashing. Give it some time, hopefully it will finish traceback.656	usleep_no_g(100)657	writeErrStr("fatal: concurrent switchToCrashStack\n")658	abort()659}660661// Disable crash stack on Windows for now. Apparently, throwing an exception662// on a non-system-allocated crash stack causes EXCEPTION_STACK_OVERFLOW and663// hangs the process (see issue 63938).664const crashStackImplemented = GOOS != "windows"665666//go:noescape667func switchToCrashStack0(fn func()) // in assembly668669func lockedOSThread() bool {670	gp := getg()671	return gp.lockedm != 0 && gp.m.lockedg != 0672}673674var (675	// allgs contains all Gs ever created (including dead Gs), and thus676	// never shrinks.677	//678	// Access via the slice is protected by allglock or stop-the-world.679	// Readers that cannot take the lock may (carefully!) use the atomic680	// variables below.681	allglock mutex682	allgs    []*g683684	// allglen and allgptr are atomic variables that contain len(allgs) and685	// &allgs[0] respectively. Proper ordering depends on totally-ordered686	// loads and stores. Writes are protected by allglock.687	//688	// allgptr is updated before allglen. Readers should read allglen689	// before allgptr to ensure that allglen is always <= len(allgptr). New690	// Gs appended during the race can be missed. For a consistent view of691	// all Gs, allglock must be held.692	//693	// allgptr copies should always be stored as a concrete type or694	// unsafe.Pointer, not uintptr, to ensure that GC can still reach it695	// even if it points to a stale array.696	allglen uintptr697	allgptr **g698)699700func allgadd(gp *g) {701	if readgstatus(gp) == _Gidle {702		throw("allgadd: bad status Gidle")703	}704705	lock(&allglock)706	allgs = append(allgs, gp)707	if &allgs[0] != allgptr {708		atomicstorep(unsafe.Pointer(&allgptr), unsafe.Pointer(&allgs[0]))709	}710	atomic.Storeuintptr(&allglen, uintptr(len(allgs)))711	unlock(&allglock)712}713714// allGsSnapshot returns a snapshot of the slice of all Gs.715//716// The world must be stopped or allglock must be held.717func allGsSnapshot() []*g {718	assertWorldStoppedOrLockHeld(&allglock)719720	// Because the world is stopped or allglock is held, allgadd721	// cannot happen concurrently with this. allgs grows722	// monotonically and existing entries never change, so we can723	// simply return a copy of the slice header. For added safety,724	// we trim everything past len because that can still change.725	return allgs[:len(allgs):len(allgs)]726}727728// atomicAllG returns &allgs[0] and len(allgs) for use with atomicAllGIndex.729func atomicAllG() (**g, uintptr) {730	length := atomic.Loaduintptr(&allglen)731	ptr := (**g)(atomic.Loadp(unsafe.Pointer(&allgptr)))732	return ptr, length733}734735// atomicAllGIndex returns ptr[i] with the allgptr returned from atomicAllG.736func atomicAllGIndex(ptr **g, i uintptr) *g {737	return *(**g)(add(unsafe.Pointer(ptr), i*goarch.PtrSize))738}739740// forEachG calls fn on every G from allgs.741//742// forEachG takes a lock to exclude concurrent addition of new Gs.743func forEachG(fn func(gp *g)) {744	lock(&allglock)745	for _, gp := range allgs {746		fn(gp)747	}748	unlock(&allglock)749}750751// forEachGRace calls fn on every G from allgs.752//753// forEachGRace avoids locking, but does not exclude addition of new Gs during754// execution, which may be missed.755func forEachGRace(fn func(gp *g)) {756	ptr, length := atomicAllG()757	for i := uintptr(0); i < length; i++ {758		gp := atomicAllGIndex(ptr, i)759		fn(gp)760	}761	return762}763764const (765	// Number of goroutine ids to grab from sched.goidgen to local per-P cache at once.766	// 16 seems to provide enough amortization, but other than that it's mostly arbitrary number.767	_GoidCacheBatch = 16768)769770// cpuinit sets up CPU feature flags and calls internal/cpu.Initialize. env should be the complete771// value of the GODEBUG environment variable.772func cpuinit(env string) {773	cpu.Initialize(env)774775	// Support cpu feature variables are used in code generated by the compiler776	// to guard execution of instructions that can not be assumed to be always supported.777	switch GOARCH {778	case "386", "amd64":779		x86HasAVX = cpu.X86.HasAVX780		x86HasFMA = cpu.X86.HasFMA781		x86HasPOPCNT = cpu.X86.HasPOPCNT782		x86HasSSE41 = cpu.X86.HasSSE41783784	case "arm":785		armHasVFPv4 = cpu.ARM.HasVFPv4786787	case "arm64":788		arm64HasATOMICS = cpu.ARM64.HasATOMICS789790	case "loong64":791		loong64HasLAMCAS = cpu.Loong64.HasLAMCAS792		loong64HasLAM_BH = cpu.Loong64.HasLAM_BH793		loong64HasDBAR_HINTS = cpu.Loong64.HasDBAR_HINTS794		loong64HasLSX = cpu.Loong64.HasLSX795796	case "riscv64":797		riscv64HasZbb = cpu.RISCV64.HasZbb798	}799}800801// getGodebugEarly extracts the environment variable GODEBUG from the environment on802// Unix-like operating systems and returns it. This function exists to extract GODEBUG803// early before much of the runtime is initialized.804//805// Returns nil, false if OS doesn't provide env vars early in the init sequence.806func getGodebugEarly() (string, bool) {807	const prefix = "GODEBUG="808	var env string809	switch GOOS {810	case "aix", "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd", "illumos", "solaris", "linux":811		// Similar to goenv_unix but extracts the environment value for812		// GODEBUG directly.813		// TODO(moehrmann): remove when general goenvs() can be called before cpuinit()814		n := int32(0)815		for argv_index(argv, argc+1+n) != nil {816			n++817		}818819		for i := int32(0); i < n; i++ {820			p := argv_index(argv, argc+1+i)821			s := unsafe.String(p, findnull(p))822823			if stringslite.HasPrefix(s, prefix) {824				env = gostringnocopy(p)[len(prefix):]825				break826			}827		}828		break829830	default:831		return "", false832	}833	return env, true834}835836// The bootstrap sequence is:837//838//	call osinit839//	call schedinit840//	make & queue new G841//	call runtime·mstart842//843// The new G calls runtime·main.844func schedinit() {845	lockInit(&sched.lock, lockRankSched)846	lockInit(&sched.sysmonlock, lockRankSysmon)847	lockInit(&sched.deferlock, lockRankDefer)848	lockInit(&sched.sudoglock, lockRankSudog)849	lockInit(&deadlock, lockRankDeadlock)850	lockInit(&paniclk, lockRankPanic)851	lockInit(&allglock, lockRankAllg)852	lockInit(&allpLock, lockRankAllp)853	lockInit(&reflectOffs.lock, lockRankReflectOffs)854	lockInit(&finlock, lockRankFin)855	lockInit(&cpuprof.lock, lockRankCpuprof)856	lockInit(&computeMaxProcsLock, lockRankComputeMaxProcs)857	allocmLock.init(lockRankAllocmR, lockRankAllocmRInternal, lockRankAllocmW)858	execLock.init(lockRankExecR, lockRankExecRInternal, lockRankExecW)859	traceLockInit()860	// Enforce that this lock is always a leaf lock.861	// All of this lock's critical sections should be862	// extremely short.863	lockInit(&memstats.heapStats.noPLock, lockRankLeafRank)864865	lockVerifyMSize()866867	sched.midle.init(unsafe.Offsetof(m{}.idleNode))868869	// raceinit must be the first call to race detector.870	// In particular, it must be done before mallocinit below calls racemapshadow.871	gp := getg()872	if raceenabled {873		gp.racectx, raceprocctx0 = raceinit()874	}875876	sched.maxmcount = 10000877	crashFD.Store(^uintptr(0))878879	// The world starts stopped.880	worldStopped()881882	godebug, parsedGodebug := getGodebugEarly()883	if parsedGodebug {884		parseRuntimeDebugVars(godebug)885	}886	ticks.init() // run as early as possible887	moduledataverify()888	stackinit()889	randinit() // must run before mallocinit, AlgInit, mcommoninit890	mallocinit()891	cpuinit(godebug) // must run before AlgInit892	maps.AlgInit()   // maps, hash, rand must not be used before this call893	mcommoninit(gp.m, -1)894	modulesinit()   // provides activeModules895	typelinksinit() // uses maps, activeModules896	itabsinit()     // uses activeModules897	stkobjinit()    // must run before GC starts898899	sigsave(&gp.m.sigmask)900	initSigmask = gp.m.sigmask901902	goargs()903	goenvs()904	secure()905	checkfds()906	if !parsedGodebug {907		// Some platforms, e.g., Windows, didn't make env vars available "early",908		// so try again now.909		parseRuntimeDebugVars(gogetenv("GODEBUG"))910	}911	finishDebugVarsSetup()912	gcinit()913914	// Allocate stack space that can be used when crashing due to bad stack915	// conditions, e.g. morestack on g0.916	gcrash.stack = stackalloc(16384)917	gcrash.stackguard0 = gcrash.stack.lo + 1000918	gcrash.stackguard1 = gcrash.stack.lo + 1000919920	// if disableMemoryProfiling is set, update MemProfileRate to 0 to turn off memprofile.921	// Note: parsedebugvars may update MemProfileRate, but when disableMemoryProfiling is922	// set to true by the linker, it means that nothing is consuming the profile, it is923	// safe to set MemProfileRate to 0.924	if disableMemoryProfiling {925		MemProfileRate = 0926	}927928	// mcommoninit runs before parsedebugvars, so init profstacks again.929	mProfStackInit(gp.m)930	defaultGOMAXPROCSInit()931932	lock(&sched.lock)933	sched.lastpoll.Store(nanotime())934	var procs int32935	if n, err := strconv.ParseInt(gogetenv("GOMAXPROCS"), 10, 32); err == nil && n > 0 {936		procs = int32(n)937		sched.customGOMAXPROCS = true938	} else {939		// Use numCPUStartup for initial GOMAXPROCS for two reasons:940		//941		// 1. We just computed it in osinit, recomputing is (minorly) wasteful.942		//943		// 2. More importantly, if debug.containermaxprocs == 0 &&944		//    debug.updatemaxprocs == 0, we want to guarantee that945		//    runtime.GOMAXPROCS(0) always equals runtime.NumCPU (which is946		//    just numCPUStartup).947		procs = defaultGOMAXPROCS(numCPUStartup)948	}949	if procresize(procs) != nil {950		throw("unknown runnable goroutine during bootstrap")951	}952	unlock(&sched.lock)953954	// World is effectively started now, as P's can run.955	worldStarted()956957	if buildVersion == "" {958		// Condition should never trigger. This code just serves959		// to ensure runtime·buildVersion is kept in the resulting binary.960		buildVersion = "unknown"961	}962	if len(modinfo) == 1 {963		// Condition should never trigger. This code just serves964		// to ensure runtime·modinfo is kept in the resulting binary.965		modinfo = ""966	}967}968969func dumpgstatus(gp *g) {970	thisg := getg()971	print("runtime:   gp: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")972	print("runtime: getg:  g=", thisg, ", goid=", thisg.goid, ",  g->atomicstatus=", readgstatus(thisg), "\n")973}974975// sched.lock must be held.976func checkmcount() {977	assertLockHeld(&sched.lock)978979	// Exclude extra M's, which are used for cgocallback from threads980	// created in C.981	//982	// The purpose of the SetMaxThreads limit is to avoid accidental fork983	// bomb from something like millions of goroutines blocking on system984	// calls, causing the runtime to create millions of threads. By985	// definition, this isn't a problem for threads created in C, so we986	// exclude them from the limit. See https://go.dev/issue/60004.987	count := mcount() - int32(extraMInUse.Load()) - int32(extraMLength.Load())988	if count > sched.maxmcount {989		print("runtime: program exceeds ", sched.maxmcount, "-thread limit\n")990		throw("thread exhaustion")991	}992}993994// mReserveID returns the next ID to use for a new m. This new m is immediately995// considered 'running' by checkdead.996//997// sched.lock must be held.998func mReserveID() int64 {999	assertLockHeld(&sched.lock)10001001	if sched.mnext+1 < sched.mnext {1002		throw("runtime: thread ID overflow")1003	}1004	id := sched.mnext1005	sched.mnext++1006	checkmcount()1007	return id1008}10091010// Pre-allocated ID may be passed as 'id', or omitted by passing -1.1011func mcommoninit(mp *m, id int64) {1012	gp := getg()10131014	// g0 stack won't make sense for user (and is not necessary unwindable).1015	if gp != gp.m.g0 {1016		callers(1, mp.createstack[:])1017	}10181019	lock(&sched.lock)10201021	if id >= 0 {1022		mp.id = id1023	} else {1024		mp.id = mReserveID()1025	}10261027	mp.self = newMWeakPointer(mp)10281029	mrandinit(mp)10301031	mpreinit(mp)1032	if mp.gsignal != nil {1033		mp.gsignal.stackguard1 = mp.gsignal.stack.lo + stackGuard1034	}10351036	// Add to allm so garbage collector doesn't free g->m1037	// when it is just in a register or thread-local storage.1038	mp.alllink = allm10391040	// NumCgoCall and others iterate over allm w/o schedlock,1041	// so we need to publish it safely.1042	atomicstorep(unsafe.Pointer(&allm), unsafe.Pointer(mp))1043	unlock(&sched.lock)10441045	// Allocate memory to hold a cgo traceback if the cgo call crashes.1046	if iscgo || GOOS == "solaris" || GOOS == "illumos" || GOOS == "windows" {1047		mp.cgoCallers = new(cgoCallers)1048	}1049	mProfStackInit(mp)1050}10511052// mProfStackInit is used to eagerly initialize stack trace buffers for1053// profiling. Lazy allocation would have to deal with reentrancy issues in1054// malloc and runtime locks for mLockProfile.1055// TODO(mknyszek): Implement lazy allocation if this becomes a problem.1056func mProfStackInit(mp *m) {1057	if debug.profstackdepth == 0 {1058		// debug.profstack is set to 0 by the user, or we're being called from1059		// schedinit before parsedebugvars.1060		return1061	}1062	mp.profStack = makeProfStackFP()1063	mp.mLockProfile.stack = makeProfStackFP()1064}10651066// makeProfStackFP creates a buffer large enough to hold a maximum-sized stack1067// trace as well as any additional frames needed for frame pointer unwinding1068// with delayed inline expansion.1069func makeProfStackFP() []uintptr {1070	// The "1" term is to account for the first stack entry being1071	// taken up by a "skip" sentinel value for profilers which1072	// defer inline frame expansion until the profile is reported.1073	// The "maxSkip" term is for frame pointer unwinding, where we1074	// want to end up with debug.profstackdebth frames but will discard1075	// some "physical" frames to account for skipping.1076	return make([]uintptr, 1+maxSkip+debug.profstackdepth)1077}10781079// makeProfStack returns a buffer large enough to hold a maximum-sized stack1080// trace.1081func makeProfStack() []uintptr { return make([]uintptr, debug.profstackdepth) }10821083//go:linkname pprof_makeProfStack1084func pprof_makeProfStack() []uintptr { return makeProfStack() }10851086func (mp *m) becomeSpinning() {1087	mp.spinning = true1088	sched.nmspinning.Add(1)1089	sched.needspinning.Store(0)1090}10911092// Take a snapshot of allp, for use after dropping the P.1093//1094// Must be called with a P, but the returned slice may be used after dropping1095// the P. The M holds a reference on the snapshot to keep the backing array1096// alive.1097//1098//go:yeswritebarrierrec1099func (mp *m) snapshotAllp() []*p {1100	mp.allpSnapshot = allp1101	return mp.allpSnapshot1102}11031104// Clear the saved allp snapshot. Should be called as soon as the snapshot is1105// no longer required.1106//1107// Must be called after reacquiring a P, as it requires a write barrier.1108//1109//go:yeswritebarrierrec1110func (mp *m) clearAllpSnapshot() {1111	mp.allpSnapshot = nil1112}11131114func (mp *m) hasCgoOnStack() bool {1115	return mp.ncgo > 0 || mp.isextra1116}11171118const (1119	// osHasLowResTimer indicates that the platform's internal timer system has a low resolution,1120	// typically on the order of 1 ms or more.1121	osHasLowResTimer = GOOS == "windows" || GOOS == "openbsd" || GOOS == "netbsd" || GOOS == "plan9"11221123	// osHasLowResClockInt is osHasLowResClock but in integer form, so it can be used to create1124	// constants conditionally.1125	osHasLowResClockInt = goos.IsWindows11261127	// osHasLowResClock indicates that timestamps produced by nanotime on the platform have a1128	// low resolution, typically on the order of 1 ms or more.1129	osHasLowResClock = osHasLowResClockInt > 01130)11311132// Mark gp ready to run.1133func ready(gp *g, traceskip int, next bool) {1134	status := readgstatus(gp)11351136	// Mark runnable.1137	mp := acquirem() // disable preemption because it can be holding p in a local var1138	if status&^_Gscan != _Gwaiting {1139		dumpgstatus(gp)1140		throw("bad g->status in ready")1141	}11421143	// status is Gwaiting or Gscanwaiting, make Grunnable and put on runq1144	trace := traceAcquire()1145	casgstatus(gp, _Gwaiting, _Grunnable)1146	if trace.ok() {1147		trace.GoUnpark(gp, traceskip)1148		traceRelease(trace)1149	}1150	runqput(mp.p.ptr(), gp, next)1151	wakep()1152	releasem(mp)1153}11541155// freezeStopWait is a large value that freezetheworld sets1156// sched.stopwait to in order to request that all Gs permanently stop.1157const freezeStopWait = 0x7fffffff11581159// freezing is set to non-zero if the runtime is trying to freeze the1160// world.1161var freezing atomic.Bool11621163// Similar to stopTheWorld but best-effort and can be called several times.1164// There is no reverse operation, used during crashing.1165// This function must not lock any mutexes.1166func freezetheworld() {1167	freezing.Store(true)1168	if debug.dontfreezetheworld > 0 {1169		// Don't prempt Ps to stop goroutines. That will perturb1170		// scheduler state, making debugging more difficult. Instead,1171		// allow goroutines to continue execution.1172		//1173		// fatalpanic will tracebackothers to trace all goroutines. It1174		// is unsafe to trace a running goroutine, so tracebackothers1175		// will skip running goroutines. That is OK and expected, we1176		// expect users of dontfreezetheworld to use core files anyway.1177		//1178		// However, allowing the scheduler to continue running free1179		// introduces a race: a goroutine may be stopped when1180		// tracebackothers checks its status, and then start running1181		// later when we are in the middle of traceback, potentially1182		// causing a crash.1183		//1184		// To mitigate this, when an M naturally enters the scheduler,1185		// schedule checks if freezing is set and if so stops1186		// execution. This guarantees that while Gs can transition from1187		// running to stopped, they can never transition from stopped1188		// to running.1189		//1190		// The sleep here allows racing Ms that missed freezing and are1191		// about to run a G to complete the transition to running1192		// before we start traceback.1193		usleep(1000)1194		return1195	}11961197	// stopwait and preemption requests can be lost1198	// due to races with concurrently executing threads,1199	// so try several times1200	for i := 0; i < 5; i++ {1201		// this should tell the scheduler to not start any new goroutines1202		sched.stopwait = freezeStopWait1203		sched.gcwaiting.Store(true)1204		// this should stop running goroutines1205		if !preemptall() {1206			break // no running goroutines1207		}1208		usleep(1000)1209	}1210	// to be sure1211	usleep(1000)1212	preemptall()1213	usleep(1000)1214}12151216// All reads and writes of g's status go through readgstatus, casgstatus1217// castogscanstatus, casfrom_Gscanstatus.1218//1219//go:nosplit1220func readgstatus(gp *g) uint32 {1221	return gp.atomicstatus.Load()1222}12231224// The Gscanstatuses are acting like locks and this releases them.1225// If it proves to be a performance hit we should be able to make these1226// simple atomic stores but for now we are going to throw if1227// we see an inconsistent state.1228func casfrom_Gscanstatus(gp *g, oldval, newval uint32) {1229	success := false12301231	// Check that transition is valid.1232	switch oldval {1233	default:1234		print("runtime: casfrom_Gscanstatus bad oldval gp=", gp, ", oldval=", hex(oldval), ", newval=", hex(newval), "\n")1235		dumpgstatus(gp)1236		throw("casfrom_Gscanstatus:top gp->status is not in scan state")1237	case _Gscanrunnable,1238		_Gscanwaiting,1239		_Gscanrunning,1240		_Gscansyscall,1241		_Gscanleaked,1242		_Gscanpreempted,1243		_Gscandeadextra:1244		if newval == oldval&^_Gscan {1245			success = gp.atomicstatus.CompareAndSwap(oldval, newval)1246		}1247	}1248	if !success {1249		print("runtime: casfrom_Gscanstatus failed gp=", gp, ", oldval=", hex(oldval), ", newval=", hex(newval), "\n")1250		dumpgstatus(gp)1251		throw("casfrom_Gscanstatus: gp->status is not in scan state")1252	}1253	releaseLockRankAndM(lockRankGscan)1254}12551256// This will return false if the gp is not in the expected status and the cas fails.1257// This acts like a lock acquire while the casfromgstatus acts like a lock release.1258func castogscanstatus(gp *g, oldval, newval uint32) bool {1259	switch oldval {1260	case _Grunnable,1261		_Grunning,1262		_Gwaiting,1263		_Gleaked,1264		_Gsyscall,1265		_Gdeadextra:1266		if newval == oldval|_Gscan {1267			r := gp.atomicstatus.CompareAndSwap(oldval, newval)1268			if r {1269				acquireLockRankAndM(lockRankGscan)1270			}1271			return r12721273		}1274	}1275	print("runtime: castogscanstatus oldval=", hex(oldval), " newval=", hex(newval), "\n")1276	throw("bad oldval passed to castogscanstatus")1277	return false1278}12791280// casgstatusAlwaysTrack is a debug flag that causes casgstatus to always track1281// various latencies on every transition instead of sampling them.1282var casgstatusAlwaysTrack = false12831284// If asked to move to or from a Gscanstatus this will throw. Use the castogscanstatus1285// and casfrom_Gscanstatus instead.1286// casgstatus will loop if the g->atomicstatus is in a Gscan status until the routine that1287// put it in the Gscan state is finished.1288//1289//go:nosplit1290func casgstatus(gp *g, oldval, newval uint32) {1291	if (oldval&_Gscan != 0) || (newval&_Gscan != 0) || oldval == newval {1292		systemstack(func() {1293			// Call on the systemstack to prevent print and throw from counting1294			// against the nosplit stack reservation.1295			print("runtime: casgstatus: oldval=", hex(oldval), " newval=", hex(newval), "\n")1296			throw("casgstatus: bad incoming values")1297		})1298	}12991300	lockWithRankMayAcquire(nil, lockRankGscan)13011302	// See https://golang.org/cl/21503 for justification of the yield delay.1303	const yieldDelay = 5 * 10001304	var nextYield int6413051306	// loop if gp->atomicstatus is in a scan state giving1307	// GC time to finish and change the state to oldval.1308	for i := 0; !gp.atomicstatus.CompareAndSwap(oldval, newval); i++ {1309		if oldval == _Gwaiting && gp.atomicstatus.Load() == _Grunnable {1310			systemstack(func() {1311				// Call on the systemstack to prevent throw from counting1312				// against the nosplit stack reservation.1313				throw("casgstatus: waiting for Gwaiting but is Grunnable")1314			})1315		}1316		if i == 0 {1317			nextYield = nanotime() + yieldDelay1318		}1319		if nanotime() < nextYield {1320			for x := 0; x < 10 && gp.atomicstatus.Load() != oldval; x++ {1321				procyield(1)1322			}1323		} else {1324			osyield()1325			nextYield = nanotime() + yieldDelay/21326		}1327	}13281329	if gp.bubble != nil {1330		systemstack(func() {1331			gp.bubble.changegstatus(gp, oldval, newval)1332		})1333	}13341335	if (oldval == _Grunning || oldval == _Gsyscall) && (newval != _Grunning && newval != _Gsyscall) {1336		// Track every gTrackingPeriod time a goroutine transitions out of _Grunning or _Gsyscall.1337		// Do not track _Grunning <-> _Gsyscall transitions, since they're two very similar states.1338		if casgstatusAlwaysTrack || gp.trackingSeq%gTrackingPeriod == 0 {1339			gp.tracking = true1340		}1341		gp.trackingSeq++1342	}1343	if !gp.tracking {1344		return1345	}13461347	// Handle various kinds of tracking.1348	//1349	// Currently:1350	// - Time spent in runnable.1351	// - Time spent blocked on a sync.Mutex or sync.RWMutex.1352	switch oldval {1353	case _Grunnable:1354		// We transitioned out of runnable, so measure how much1355		// time we spent in this state and add it to1356		// runnableTime.1357		now := nanotime()1358		gp.runnableTime += now - gp.trackingStamp1359		gp.trackingStamp = 01360	case _Gwaiting:1361		if !gp.waitreason.isMutexWait() {1362			// Not blocking on a lock.1363			break1364		}1365		// Blocking on a lock, measure it. Note that because we're1366		// sampling, we have to multiply by our sampling period to get1367		// a more representative estimate of the absolute value.1368		// gTrackingPeriod also represents an accurate sampling period1369		// because we can only enter this state from _Grunning.1370		now := nanotime()1371		sched.totalMutexWaitTime.Add((now - gp.trackingStamp) * gTrackingPeriod)1372		gp.trackingStamp = 01373	}1374	switch newval {1375	case _Gwaiting:1376		if !gp.waitreason.isMutexWait() {1377			// Not blocking on a lock.1378			break1379		}1380		// Blocking on a lock. Write down the timestamp.1381		now := nanotime()1382		gp.trackingStamp = now1383	case _Grunnable:1384		// We just transitioned into runnable, so record what1385		// time that happened.1386		now := nanotime()1387		gp.trackingStamp = now1388	case _Grunning:1389		// We're transitioning into running, so turn off1390		// tracking and record how much time we spent in1391		// runnable.1392		gp.tracking = false1393		sched.timeToRun.record(gp.runnableTime)1394		gp.runnableTime = 01395	}1396}13971398// casGToWaiting transitions gp from old to _Gwaiting, and sets the wait reason.1399//1400// Use this over casgstatus when possible to ensure that a waitreason is set.1401func casGToWaiting(gp *g, old uint32, reason waitReason) {1402	// Set the wait reason before calling casgstatus, because casgstatus will use it.1403	gp.waitreason = reason1404	casgstatus(gp, old, _Gwaiting)1405}14061407// casGToWaitingForSuspendG transitions gp from old to _Gwaiting, and sets the wait reason.1408// The wait reason must be a valid isWaitingForSuspendG wait reason.1409//1410// While a goroutine is in this state, it's stack is effectively pinned.1411// The garbage collector must not shrink or otherwise mutate the goroutine's stack.1412//1413// Use this over casgstatus when possible to ensure that a waitreason is set.1414func casGToWaitingForSuspendG(gp *g, old uint32, reason waitReason) {1415	if !reason.isWaitingForSuspendG() {1416		throw("casGToWaitingForSuspendG with non-isWaitingForSuspendG wait reason")1417	}1418	casGToWaiting(gp, old, reason)1419}14201421// casGToPreemptScan transitions gp from _Grunning to _Gscan|_Gpreempted.1422//1423// TODO(austin): This is the only status operation that both changes1424// the status and locks the _Gscan bit. Rethink this.1425func casGToPreemptScan(gp *g, old, new uint32) {1426	if old != _Grunning || new != _Gscan|_Gpreempted {1427		throw("bad g transition")1428	}1429	acquireLockRankAndM(lockRankGscan)1430	for !gp.atomicstatus.CompareAndSwap(_Grunning, _Gscan|_Gpreempted) {1431	}1432	// We never notify gp.bubble that the goroutine state has moved1433	// from _Grunning to _Gpreempted. We call bubble.changegstatus1434	// after status changes happen, but doing so here would violate the1435	// ordering between the gscan and synctest locks. The bubble doesn't1436	// distinguish between _Grunning and _Gpreempted anyway, so not1437	// notifying it is fine.1438}14391440// casGFromPreempted attempts to transition gp from _Gpreempted to1441// _Gwaiting. If successful, the caller is responsible for1442// re-scheduling gp.1443func casGFromPreempted(gp *g, old, new uint32) bool {1444	if old != _Gpreempted || new != _Gwaiting {1445		throw("bad g transition")1446	}1447	gp.waitreason = waitReasonPreempted1448	if !gp.atomicstatus.CompareAndSwap(_Gpreempted, _Gwaiting) {1449		return false1450	}1451	if bubble := gp.bubble; bubble != nil {1452		bubble.changegstatus(gp, _Gpreempted, _Gwaiting)1453	}1454	return true1455}14561457// stwReason is an enumeration of reasons the world is stopping.1458type stwReason uint814591460// Reasons to stop-the-world.1461//1462// Avoid reusing reasons and add new ones instead.1463const (1464	stwUnknown                     stwReason = iota // "unknown"1465	stwGCMarkTerm                                   // "GC mark termination"1466	stwGCSweepTerm                                  // "GC sweep termination"1467	stwWriteHeapDump                                // "write heap dump"1468	stwGoroutineProfile                             // "goroutine profile"1469	stwGoroutineProfileCleanup                      // "goroutine profile cleanup"1470	stwAllGoroutinesStack                           // "all goroutines stack trace"1471	stwReadMemStats                                 // "read mem stats"1472	stwAllThreadsSyscall                            // "AllThreadsSyscall"1473	stwGOMAXPROCS                                   // "GOMAXPROCS"1474	stwStartTrace                                   // "start trace"1475	stwStopTrace                                    // "stop trace"1476	stwForTestCountPagesInUse                       // "CountPagesInUse (test)"1477	stwForTestReadMetricsSlow                       // "ReadMetricsSlow (test)"1478	stwForTestReadMemStatsSlow                      // "ReadMemStatsSlow (test)"1479	stwForTestPageCachePagesLeaked                  // "PageCachePagesLeaked (test)"1480	stwForTestResetDebugLog                         // "ResetDebugLog (test)"1481)14821483func (r stwReason) String() string {1484	return stwReasonStrings[r]1485}14861487func (r stwReason) isGC() bool {1488	return r == stwGCMarkTerm || r == stwGCSweepTerm1489}14901491// If you add to this list, also add it to src/internal/trace/parser.go.1492// If you change the values of any of the stw* constants, bump the trace1493// version number and make a copy of this.1494var stwReasonStrings = [...]string{1495	stwUnknown:                     "unknown",1496	stwGCMarkTerm:                  "GC mark termination",1497	stwGCSweepTerm:                 "GC sweep termination",1498	stwWriteHeapDump:               "write heap dump",1499	stwGoroutineProfile:            "goroutine profile",1500	stwGoroutineProfileCleanup:     "goroutine profile cleanup",1501	stwAllGoroutinesStack:          "all goroutines stack trace",1502	stwReadMemStats:                "read mem stats",1503	stwAllThreadsSyscall:           "AllThreadsSyscall",1504	stwGOMAXPROCS:                  "GOMAXPROCS",1505	stwStartTrace:                  "start trace",1506	stwStopTrace:                   "stop trace",1507	stwForTestCountPagesInUse:      "CountPagesInUse (test)",1508	stwForTestReadMetricsSlow:      "ReadMetricsSlow (test)",1509	stwForTestReadMemStatsSlow:     "ReadMemStatsSlow (test)",1510	stwForTestPageCachePagesLeaked: "PageCachePagesLeaked (test)",1511	stwForTestResetDebugLog:        "ResetDebugLog (test)",1512}15131514// worldStop provides context from the stop-the-world required by the1515// start-the-world.1516type worldStop struct {1517	reason           stwReason1518	startedStopping  int641519	finishedStopping int641520	stoppingCPUTime  int641521}15221523// Temporary variable for stopTheWorld, when it can't write to the stack.1524//1525// Protected by worldsema.1526var stopTheWorldContext worldStop15271528// stopTheWorld stops all P's from executing goroutines, interrupting1529// all goroutines at GC safe points and records reason as the reason1530// for the stop. On return, only the current goroutine's P is running.1531// stopTheWorld must not be called from a system stack and the caller1532// must not hold worldsema. The caller must call startTheWorld when1533// other P's should resume execution.1534//1535// stopTheWorld is safe for multiple goroutines to call at the1536// same time. Each will execute its own stop, and the stops will1537// be serialized.1538//1539// This is also used by routines that do stack dumps. If the system is1540// in panic or being exited, this may not reliably stop all1541// goroutines.1542//1543// Returns the STW context. When starting the world, this context must be1544// passed to startTheWorld.1545func stopTheWorld(reason stwReason) worldStop {1546	semacquire(&worldsema)1547	gp := getg()1548	gp.m.preemptoff = reason.String()1549	systemstack(func() {1550		stopTheWorldContext = stopTheWorldWithSema(reason) // avoid write to stack1551	})1552	return stopTheWorldContext1553}15541555// startTheWorld undoes the effects of stopTheWorld.1556//1557// w must be the worldStop returned by stopTheWorld.1558func startTheWorld(w worldStop) {1559	systemstack(func() { startTheWorldWithSema(0, w) })15601561	// worldsema must be held over startTheWorldWithSema to ensure1562	// gomaxprocs cannot change while worldsema is held.1563	//1564	// Release worldsema with direct handoff to the next waiter, but1565	// acquirem so that semrelease1 doesn't try to yield our time.1566	//1567	// Otherwise if e.g. ReadMemStats is being called in a loop,1568	// it might stomp on other attempts to stop the world, such as1569	// for starting or ending GC. The operation this blocks is1570	// so heavy-weight that we should just try to be as fair as1571	// possible here.1572	//1573	// We don't want to just allow us to get preempted between now1574	// and releasing the semaphore because then we keep everyone1575	// (including, for example, GCs) waiting longer.1576	mp := acquirem()1577	mp.preemptoff = ""1578	semrelease1(&worldsema, true, 0)1579	releasem(mp)1580}15811582// stopTheWorldGC has the same effect as stopTheWorld, but blocks1583// until the GC is not running. It also blocks a GC from starting1584// until startTheWorldGC is called.1585func stopTheWorldGC(reason stwReason) worldStop {1586	semacquire(&gcsema)1587	return stopTheWorld(reason)1588}15891590// startTheWorldGC undoes the effects of stopTheWorldGC.1591//1592// w must be the worldStop returned by stopTheWorld.1593func startTheWorldGC(w worldStop) {1594	startTheWorld(w)1595	semrelease(&gcsema)1596}15971598// Holding worldsema grants an M the right to try to stop the world.1599var worldsema uint32 = 116001601// Holding gcsema grants the M the right to block a GC, and blocks1602// until the current GC is done. In particular, it prevents gomaxprocs1603// from changing concurrently.1604//1605// TODO(mknyszek): Once gomaxprocs and the execution tracer can handle1606// being changed/enabled during a GC, remove this.1607var gcsema uint32 = 116081609// stopTheWorldWithSema is the core implementation of stopTheWorld.1610// The caller is responsible for acquiring worldsema and disabling1611// preemption first and then should stopTheWorldWithSema on the system1612// stack:1613//1614//	semacquire(&worldsema, 0)1615//	m.preemptoff = "reason"1616//	var stw worldStop1617//	systemstack(func() {1618//		stw = stopTheWorldWithSema(reason)1619//	})1620//1621// When finished, the caller must either call startTheWorld or undo1622// these three operations separately:1623//1624//	m.preemptoff = ""1625//	systemstack(func() {1626//		now = startTheWorldWithSema(stw)1627//	})1628//	semrelease(&worldsema)1629//1630// It is allowed to acquire worldsema once and then execute multiple1631// startTheWorldWithSema/stopTheWorldWithSema pairs.1632// Other P's are able to execute between successive calls to1633// startTheWorldWithSema and stopTheWorldWithSema.1634// Holding worldsema causes any other goroutines invoking1635// stopTheWorld to block.1636//1637// Returns the STW context. When starting the world, this context must be1638// passed to startTheWorldWithSema.1639//1640//go:systemstack1641func stopTheWorldWithSema(reason stwReason) worldStop {1642	// Mark the goroutine which called stopTheWorld preemptible so its1643	// stack may be scanned by the GC or observed by the execution tracer.1644	//1645	// This lets a mark worker scan us or the execution tracer take our1646	// stack while we try to stop the world since otherwise we could get1647	// in a mutual preemption deadlock.1648	//1649	// casGToWaitingForSuspendG marks the goroutine as ineligible for a1650	// stack shrink, effectively pinning the stack in memory for the duration.1651	//1652	// N.B. The execution tracer is not aware of this status transition and1653	// handles it specially based on the wait reason.1654	casGToWaitingForSuspendG(getg().m.curg, _Grunning, waitReasonStoppingTheWorld)16551656	trace := traceAcquire()1657	if trace.ok() {1658		trace.STWStart(reason)1659		traceRelease(trace)1660	}1661	gp := getg()16621663	// If we hold a lock, then we won't be able to stop another M1664	// that is blocked trying to acquire the lock.1665	if gp.m.locks > 0 {1666		throw("stopTheWorld: holding locks")1667	}16681669	lock(&sched.lock)1670	start := nanotime() // exclude time waiting for sched.lock from start and total time metrics.1671	sched.stopwait = gomaxprocs1672	sched.gcwaiting.Store(true)1673	preemptall()16741675	// Stop current P.1676	gp.m.p.ptr().status = _Pgcstop // Pgcstop is only diagnostic.1677	gp.m.p.ptr().gcStopTime = start1678	sched.stopwait--16791680	// Try to retake all P's in syscalls.1681	for _, pp := range allp {1682		if thread, ok := setBlockOnExitSyscall(pp); ok {1683			thread.gcstopP()1684			thread.resume()1685		}1686	}16871688	// Stop idle Ps.1689	now := nanotime()1690	for {1691		pp, _ := pidleget(now)1692		if pp == nil {1693			break1694		}1695		pp.status = _Pgcstop1696		pp.gcStopTime = nanotime()1697		sched.stopwait--1698	}1699	wait := sched.stopwait > 01700	unlock(&sched.lock)17011702	// Wait for remaining Ps to stop voluntarily.1703	if wait {1704		for {1705			// wait for 100us, then try to re-preempt in case of any races1706			if notetsleep(&sched.stopnote, 100*1000) {1707				noteclear(&sched.stopnote)1708				break1709			}1710			preemptall()1711		}1712	}17131714	finish := nanotime()1715	startTime := finish - start1716	if reason.isGC() {1717		sched.stwStoppingTimeGC.record(startTime)1718	} else {1719		sched.stwStoppingTimeOther.record(startTime)1720	}17211722	// Double-check we actually stopped everything, and all the invariants hold.1723	// Also accumulate all the time spent by each P in _Pgcstop up to the point1724	// where everything was stopped. This will be accumulated into the total pause1725	// CPU time by the caller.1726	stoppingCPUTime := int64(0)1727	bad := ""1728	if sched.stopwait != 0 {1729		bad = "stopTheWorld: not stopped (stopwait != 0)"1730	} else {1731		for _, pp := range allp {1732			if pp.status != _Pgcstop {1733				bad = "stopTheWorld: not stopped (status != _Pgcstop)"1734			}1735			if pp.gcStopTime == 0 && bad == "" {1736				bad = "stopTheWorld: broken CPU time accounting"1737			}1738			stoppingCPUTime += finish - pp.gcStopTime1739			pp.gcStopTime = 01740		}1741	}1742	if freezing.Load() {1743		// Some other thread is panicking. This can cause the1744		// sanity checks above to fail if the panic happens in1745		// the signal handler on a stopped thread. Either way,1746		// we should halt this thread.1747		lock(&deadlock)1748		lock(&deadlock)1749	}1750	if bad != "" {1751		throw(bad)1752	}17531754	worldStopped()17551756	// Switch back to _Grunning, now that the world is stopped.1757	casgstatus(getg().m.curg, _Gwaiting, _Grunning)17581759	return worldStop{1760		reason:           reason,1761		startedStopping:  start,1762		finishedStopping: finish,1763		stoppingCPUTime:  stoppingCPUTime,1764	}1765}17661767// reason is the same STW reason passed to stopTheWorld. start is the start1768// time returned by stopTheWorld.1769//1770// now is the current time; prefer to pass 0 to capture a fresh timestamp.1771//1772// stattTheWorldWithSema returns now.1773func startTheWorldWithSema(now int64, w worldStop) int64 {1774	assertWorldStopped()17751776	mp := acquirem() // disable preemption because it can be holding p in a local var1777	if netpollinited() {1778		list, delta := netpoll(0) // non-blocking1779		injectglist(&list)1780		netpollAdjustWaiters(delta)1781	}1782	lock(&sched.lock)17831784	procs := gomaxprocs1785	if newprocs != 0 {1786		procs = newprocs1787		newprocs = 01788	}1789	p1 := procresize(procs)1790	sched.gcwaiting.Store(false)1791	if sched.sysmonwait.Load() {1792		sched.sysmonwait.Store(false)1793		notewakeup(&sched.sysmonnote)1794	}1795	unlock(&sched.lock)17961797	worldStarted()17981799	for p1 != nil {1800		p := p11801		p1 = p1.link.ptr()1802		if p.m != 0 {1803			mp := p.m.ptr()1804			p.m = 01805			if mp.nextp != 0 {1806				throw("startTheWorld: inconsistent mp->nextp")1807			}1808			mp.nextp.set(p)1809			notewakeup(&mp.park)1810		} else {1811			// Start M to run P.  Do not start another M below.1812			newm(nil, p, -1)1813		}1814	}18151816	// Capture start-the-world time before doing clean-up tasks.1817	if now == 0 {1818		now = nanotime()1819	}1820	totalTime := now - w.startedStopping1821	if w.reason.isGC() {1822		sched.stwTotalTimeGC.record(totalTime)1823	} else {1824		sched.stwTotalTimeOther.record(totalTime)1825	}1826	trace := traceAcquire()1827	if trace.ok() {1828		trace.STWDone()1829		traceRelease(trace)1830	}18311832	// Wakeup an additional proc in case we have excessive runnable goroutines1833	// in local queues or in the global queue. If we don't, the proc will park itself.1834	// If we have lots of excessive work, resetspinning will unpark additional procs as necessary.1835	wakep()18361837	releasem(mp)18381839	return now1840}18411842// usesLibcall indicates whether this runtime performs system calls1843// via libcall.1844func usesLibcall() bool {1845	switch GOOS {1846	case "aix", "darwin", "illumos", "ios", "openbsd", "solaris", "windows":1847		return true1848	}1849	return false1850}18511852// mStackIsSystemAllocated indicates whether this runtime starts on a1853// system-allocated stack.1854func mStackIsSystemAllocated() bool {1855	switch GOOS {1856	case "aix", "darwin", "plan9", "illumos", "ios", "openbsd", "solaris", "windows":1857		return true1858	}1859	return false1860}18611862// mstart is the entry-point for new Ms.1863// It is written in assembly, uses ABI0, is marked TOPFRAME, and calls mstart0.1864func mstart()18651866// mstart0 is the Go entry-point for new Ms.1867// This must not split the stack because we may not even have stack1868// bounds set up yet.1869//1870// May run during STW (because it doesn't have a P yet), so write1871// barriers are not allowed.1872//1873//go:nosplit1874//go:nowritebarrierrec1875func mstart0() {1876	gp := getg()18771878	osStack := gp.stack.lo == 01879	if osStack {1880		// Initialize stack bounds from system stack.1881		// Cgo may have left stack size in stack.hi.1882		// minit may update the stack bounds.1883		//1884		// Note: these bounds may not be very accurate.1885		// We set hi to &size, but there are things above1886		// it. The 1024 is supposed to compensate this,1887		// but is somewhat arbitrary.1888		size := gp.stack.hi1889		if size == 0 {1890			size = 16384 * sys.StackGuardMultiplier1891		}1892		gp.stack.hi = uintptr(noescape(unsafe.Pointer(&size)))1893		gp.stack.lo = gp.stack.hi - size + 10241894	}1895	// Initialize stack guard so that we can start calling regular1896	// Go code.1897	gp.stackguard0 = gp.stack.lo + stackGuard1898	// This is the g0, so we can also call go:systemstack1899	// functions, which check stackguard1.1900	gp.stackguard1 = gp.stackguard01901	mstart1()19021903	// Exit this thread.1904	if mStackIsSystemAllocated() {1905		// Windows, Solaris, illumos, Darwin, AIX and Plan 9 always system-allocate1906		// the stack, but put it in gp.stack before mstart,1907		// so the logic above hasn't set osStack yet.1908		osStack = true1909	}1910	mexit(osStack)1911}19121913// The go:noinline is to guarantee the sys.GetCallerPC/sys.GetCallerSP below are safe,1914// so that we can set up g0.sched to return to the call of mstart1 above.1915//1916//go:noinline1917func mstart1() {1918	gp := getg()19191920	if gp != gp.m.g0 {1921		throw("bad runtime·mstart")1922	}19231924	// Set up m.g0.sched as a label returning to just1925	// after the mstart1 call in mstart0 above, for use by goexit0 and mcall.1926	// We're never coming back to mstart1 after we call schedule,1927	// so other calls can reuse the current frame.1928	// And goexit0 does a gogo that needs to return from mstart11929	// and let mstart0 exit the thread.1930	gp.sched.g = guintptr(unsafe.Pointer(gp))1931	gp.sched.pc = sys.GetCallerPC()1932	gp.sched.sp = sys.GetCallerSP()1933	gp.sched.bp = getcallerfp()19341935	asminit()1936	minit()19371938	// Install signal handlers; after minit so that minit can1939	// prepare the thread to be able to handle the signals.1940	if gp.m == &m0 {1941		mstartm0()1942	}19431944	if debug.dataindependenttiming == 1 {1945		sys.EnableDIT()1946	}19471948	if fn := gp.m.mstartfn; fn != nil {1949		fn()1950	}19511952	if gp.m != &m0 {1953		acquirep(gp.m.nextp.ptr())1954		gp.m.nextp = 01955	}1956	schedule()1957}19581959// mstartm0 implements part of mstart1 that only runs on the m0.1960//1961// Write barriers are allowed here because we know the GC can't be1962// running yet, so they'll be no-ops.1963//1964//go:yeswritebarrierrec1965func mstartm0() {1966	// Create an extra M for callbacks on threads not created by Go.1967	// An extra M is also needed on Windows for callbacks created by1968	// syscall.NewCallback. See issue #6751 for details.1969	if (iscgo || GOOS == "windows") && !cgoHasExtraM {1970		cgoHasExtraM = true1971		newextram()1972	}1973	initsig(false)1974}19751976// mPark causes a thread to park itself, returning once woken.1977//1978//go:nosplit1979func mPark() {1980	gp := getg()1981	// This M might stay parked through an entire GC cycle.1982	// Erase any leftovers on the signal stack.1983	if goexperiment.RuntimeSecret {1984		eraseSecretsSignalStk()1985	}1986	notesleep(&gp.m.park)1987	noteclear(&gp.m.park)1988}19891990// mexit tears down and exits the current thread.1991//1992// Don't call this directly to exit the thread, since it must run at1993// the top of the thread stack. Instead, use gogo(&gp.m.g0.sched) to1994// unwind the stack to the point that exits the thread.1995//1996// It is entered with m.p != nil, so write barriers are allowed. It1997// will release the P before exiting.1998//1999//go:yeswritebarrierrec2000func mexit(osStack bool) {

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.