Source file
src/runtime/proc.go
1
2
3
4
5 package runtime
6
7 import (
8 "internal/abi"
9 "internal/cpu"
10 "internal/goarch"
11 "internal/goexperiment"
12 "internal/runtime/atomic"
13 "internal/runtime/exithook"
14 "internal/runtime/maps"
15 "internal/runtime/sys"
16 "internal/strconv"
17 "internal/stringslite"
18 "unsafe"
19 )
20
21
22 var modinfo string
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118 var (
119 m0 m
120 g0 g
121 mcache0 *mcache
122 raceprocctx0 uintptr
123 raceFiniLock mutex
124 )
125
126
127
128 var runtime_inittasks []*initTask
129
130
131
132 var mainInitDone atomic.Bool
133
134
135
136
137 var mainInitDoneChan chan bool
138
139
140 func main_main()
141
142
143 var mainStarted bool
144
145
146 var runtimeInitTime int64
147
148
149 var initSigmask sigset
150
151
152 func main() {
153 mp := getg().m
154
155
156
157 mp.g0.racectx = 0
158
159
160
161
162 if goarch.PtrSize == 8 {
163 maxstacksize = 1000000000
164 } else {
165 maxstacksize = 250000000
166 }
167
168
169
170
171 maxstackceiling = 2 * maxstacksize
172
173
174 mainStarted = true
175
176 if haveSysmon {
177 systemstack(func() {
178 newm(sysmon, nil, -1)
179 })
180 }
181
182
183
184
185
186
187
188 lockOSThread()
189
190 if mp != &m0 {
191 throw("runtime.main not on m0")
192 }
193
194
195
196 runtimeInitTime = nanotime()
197 if runtimeInitTime == 0 {
198 throw("nanotime returning zero")
199 }
200
201 if debug.inittrace != 0 {
202 inittrace.id = getg().goid
203 inittrace.active = true
204 }
205
206 doInit(runtime_inittasks)
207
208
209 needUnlock := true
210 defer func() {
211 if needUnlock {
212 unlockOSThread()
213 }
214 }()
215
216 gcenable()
217 defaultGOMAXPROCSUpdateEnable()
218
219
220 if k := invalidGODEBUG.key; k != "" {
221 v := invalidGODEBUG.value
222 r := strconv.Itoa(invalidGODEBUG.removed)
223 fatal(`removed GODEBUG "` + k + `" set to old value "` + v + `" in environment (https://go.dev/doc/godebug#go-1` + r + `)`)
224 }
225
226 mainInitDoneChan = make(chan bool)
227 if iscgo {
228 if _cgo_pthread_key_created == nil {
229 throw("_cgo_pthread_key_created missing")
230 }
231
232 if GOOS != "windows" {
233 if _cgo_thread_start == nil {
234 throw("_cgo_thread_start missing")
235 }
236 if _cgo_setenv == nil {
237 throw("_cgo_setenv missing")
238 }
239 if _cgo_unsetenv == nil {
240 throw("_cgo_unsetenv missing")
241 }
242 }
243 if _cgo_notify_runtime_init_done == nil {
244 throw("_cgo_notify_runtime_init_done missing")
245 }
246
247
248 if set_crosscall2 == nil {
249 throw("set_crosscall2 missing")
250 }
251 set_crosscall2()
252
253
254
255 startTemplateThread()
256 cgocall(_cgo_notify_runtime_init_done, nil)
257 }
258
259
260
261
262
263
264
265
266 last := lastmoduledatap
267 for m := &firstmoduledata; true; m = m.next {
268 doInit(m.inittasks)
269 if m == last {
270 break
271 }
272 }
273
274
275
276 inittrace.active = false
277
278 mainInitDone.Store(true)
279 close(mainInitDoneChan)
280
281 needUnlock = false
282 unlockOSThread()
283
284 if isarchive || islibrary {
285
286
287 if GOARCH == "wasm" {
288
289
290
291
292
293
294
295 pause(sys.GetCallerSP() - 16)
296 panic("unreachable")
297 }
298 return
299 }
300 fn := main_main
301 fn()
302
303
304
305
306
307
308
309
310 exitHooksRun := false
311 if asanenabled && (isarchive || islibrary || NumCgoCall() > 1) {
312 runExitHooks(0)
313 exitHooksRun = true
314 lsandoleakcheck()
315 }
316
317
318
319
320
321 if runningPanicDefers.Load() != 0 {
322
323 for c := 0; c < 1000; c++ {
324 if runningPanicDefers.Load() == 0 {
325 break
326 }
327 Gosched()
328 }
329 }
330 if panicking.Load() != 0 {
331 gopark(nil, nil, waitReasonPanicWait, traceBlockForever, 1)
332 }
333 if !exitHooksRun {
334 runExitHooks(0)
335 }
336 if raceenabled {
337 racefini()
338 }
339
340 exit(0)
341 for {
342 var x *int32
343 *x = 0
344 }
345 }
346
347
348
349
350 func os_beforeExit(exitCode int) {
351 runExitHooks(exitCode)
352 if exitCode == 0 && raceenabled {
353 racefini()
354 }
355
356
357 if exitCode == 0 && asanenabled && (isarchive || islibrary || NumCgoCall() > 1) {
358 lsandoleakcheck()
359 }
360 }
361
362 func init() {
363 exithook.Gosched = Gosched
364 exithook.Goid = func() uint64 { return getg().goid }
365 exithook.Throw = throw
366 }
367
368 func runExitHooks(code int) {
369 exithook.Run(code)
370 }
371
372
373 func init() {
374 go forcegchelper()
375 }
376
377 func forcegchelper() {
378 forcegc.g = getg()
379 lockInit(&forcegc.lock, lockRankForcegc)
380 for {
381 lock(&forcegc.lock)
382 if forcegc.idle.Load() {
383 throw("forcegc: phase error")
384 }
385 forcegc.idle.Store(true)
386 goparkunlock(&forcegc.lock, waitReasonForceGCIdle, traceBlockSystemGoroutine, 1)
387
388 if debug.gctrace > 0 {
389 println("GC forced")
390 }
391
392 gcStart(gcTrigger{kind: gcTriggerTime, now: nanotime()})
393 }
394 }
395
396
397
398
399
400 func Gosched() {
401 checkTimeouts()
402 mcall(gosched_m)
403 }
404
405
406
407
408
409 func goschedguarded() {
410 mcall(goschedguarded_m)
411 }
412
413
414
415
416
417
418 func goschedIfBusy() {
419 gp := getg()
420
421
422 if !gp.preempt && sched.npidle.Load() > 0 {
423 return
424 }
425 mcall(gosched_m)
426 }
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456 func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason waitReason, traceReason traceBlockReason, traceskip int) {
457 if reason != waitReasonSleep {
458 checkTimeouts()
459 }
460 mp := acquirem()
461 gp := mp.curg
462 status := readgstatus(gp)
463 if status != _Grunning && status != _Gscanrunning {
464 throw("gopark: bad g status")
465 }
466 mp.waitlock = lock
467 mp.waitunlockf = unlockf
468 gp.waitreason = reason
469 mp.waitTraceBlockReason = traceReason
470 mp.waitTraceSkip = traceskip
471 releasem(mp)
472
473 mcall(park_m)
474 }
475
476
477
478 func goparkunlock(lock *mutex, reason waitReason, traceReason traceBlockReason, traceskip int) {
479 gopark(parkunlock_c, unsafe.Pointer(lock), reason, traceReason, traceskip)
480 }
481
482
483
484
485
486
487
488
489
490
491
492 func goready(gp *g, traceskip int) {
493 systemstack(func() {
494 ready(gp, traceskip, true)
495 })
496 }
497
498
499 func acquireWaitingG(typ waitingGType) *waitingG {
500
501
502
503
504
505
506
507
508 mp := acquirem()
509 pp := mp.p.ptr()
510 if len(pp.waitingGCache) == 0 {
511 lock(&sched.waitingGLock)
512
513 for len(pp.waitingGCache) < cap(pp.waitingGCache)/2 && sched.waitingGCache != nil {
514 wg := sched.waitingGCache
515 sched.waitingGCache = wg.next
516 wg.next = nil
517 pp.waitingGCache = append(pp.waitingGCache, wg)
518 }
519 unlock(&sched.waitingGLock)
520
521 if len(pp.waitingGCache) == 0 {
522 pp.waitingGCache = append(pp.waitingGCache, new(waitingG))
523 }
524 }
525 n := len(pp.waitingGCache)
526 wg := pp.waitingGCache[n-1]
527 pp.waitingGCache[n-1] = nil
528 pp.waitingGCache = pp.waitingGCache[:n-1]
529 if wg.typ != waitingGTypeNone {
530 throw("acquireWaitingG: found wg.typ != waitingGTypeNone in cache")
531 }
532 if wg.elem.get() != nil {
533 throw("acquireWaitingG: found wg.elem != nil in cache")
534 }
535 wg.typ = typ
536 releasem(mp)
537 return wg
538 }
539
540
541 func releaseWaitingG(wg *waitingG) {
542 if wg.typ == waitingGTypeNone {
543 throw("runtime: waitingG without type")
544 }
545 if wg.elem.get() != nil {
546 throw("runtime: waitingG with non-nil elem")
547 }
548 if wg.isSelect {
549 throw("runtime: waitingG with non-false isSelect")
550 }
551 if wg.next != nil {
552 throw("runtime: waitingG with non-nil next")
553 }
554 if wg.prev != nil {
555 throw("runtime: waitingG with non-nil prev")
556 }
557 if wg.waitlink != nil {
558 throw("runtime: waitingG with non-nil waitlink")
559 }
560 if wg.c.get() != nil {
561 throw("runtime: waitingG with non-nil c")
562 }
563 wg.typ = waitingGTypeNone
564 gp := getg()
565 if gp.param != nil {
566 throw("runtime: releaseWaitingG with non-nil gp.param")
567 }
568 mp := acquirem()
569 pp := mp.p.ptr()
570 if len(pp.waitingGCache) == cap(pp.waitingGCache) {
571
572 var first, last *waitingG
573 for len(pp.waitingGCache) > cap(pp.waitingGCache)/2 {
574 n := len(pp.waitingGCache)
575 p := pp.waitingGCache[n-1]
576 pp.waitingGCache[n-1] = nil
577 pp.waitingGCache = pp.waitingGCache[:n-1]
578 if first == nil {
579 first = p
580 } else {
581 last.next = p
582 }
583 last = p
584 }
585 lock(&sched.waitingGLock)
586 last.next = sched.waitingGCache
587 sched.waitingGCache = first
588 unlock(&sched.waitingGLock)
589 }
590 pp.waitingGCache = append(pp.waitingGCache, wg)
591 releasem(mp)
592 }
593
594
595 func badmcall(fn func(*g)) {
596 throw("runtime: mcall called on m->g0 stack")
597 }
598
599 func badmcall2(fn func(*g)) {
600 throw("runtime: mcall function returned")
601 }
602
603 func badreflectcall() {
604 panic(plainError("arg size to reflect.call more than 1GB"))
605 }
606
607
608
609 func badmorestackg0() {
610 if !crashStackImplemented {
611 writeErrStr("fatal: morestack on g0\n")
612 return
613 }
614
615 g := getg()
616 switchToCrashStack(func() {
617 print("runtime: morestack on g0, stack [", hex(g.stack.lo), " ", hex(g.stack.hi), "], sp=", hex(g.sched.sp), ", called from\n")
618 g.m.traceback = 2
619 traceback1(g.sched.pc, g.sched.sp, g.sched.lr, g, 0)
620 print("\n")
621
622 throw("morestack on g0")
623 })
624 }
625
626
627
628 func badmorestackgsignal() {
629 writeErrStr("fatal: morestack on gsignal\n")
630 }
631
632
633 func badctxt() {
634 throw("ctxt != 0")
635 }
636
637
638
639 var gcrash g
640
641 var crashingG atomic.Pointer[g]
642
643
644
645
646
647
648
649
650
651 func switchToCrashStack(fn func()) {
652 me := getg()
653 if crashingG.CompareAndSwapNoWB(nil, me) {
654 switchToCrashStack0(fn)
655 abort()
656 }
657 if crashingG.Load() == me {
658
659 writeErrStr("fatal: recursive switchToCrashStack\n")
660 abort()
661 }
662
663 usleep_no_g(100)
664 writeErrStr("fatal: concurrent switchToCrashStack\n")
665 abort()
666 }
667
668
669
670
671 const crashStackImplemented = GOOS != "windows"
672
673
674 func switchToCrashStack0(fn func())
675
676 func lockedOSThread() bool {
677 gp := getg()
678 return gp.lockedm != 0 && gp.m.lockedg != 0
679 }
680
681 var (
682
683
684
685
686
687
688 allglock mutex
689 allgs []*g
690
691
692
693
694
695
696
697
698
699
700
701
702
703 allglen uintptr
704 allgptr **g
705 )
706
707 func allgadd(gp *g) {
708 if readgstatus(gp) == _Gidle {
709 throw("allgadd: bad status Gidle")
710 }
711
712 lock(&allglock)
713 allgs = append(allgs, gp)
714 if &allgs[0] != allgptr {
715 atomicstorep(unsafe.Pointer(&allgptr), unsafe.Pointer(&allgs[0]))
716 }
717 atomic.Storeuintptr(&allglen, uintptr(len(allgs)))
718 unlock(&allglock)
719 }
720
721
722
723
724 func allGsSnapshot() []*g {
725 assertWorldStoppedOrLockHeld(&allglock)
726
727
728
729
730
731
732 return allgs[:len(allgs):len(allgs)]
733 }
734
735
736 func atomicAllG() (**g, uintptr) {
737 length := atomic.Loaduintptr(&allglen)
738 ptr := (**g)(atomic.Loadp(unsafe.Pointer(&allgptr)))
739 return ptr, length
740 }
741
742
743 func atomicAllGIndex(ptr **g, i uintptr) *g {
744 return *(**g)(add(unsafe.Pointer(ptr), i*goarch.PtrSize))
745 }
746
747
748
749
750 func forEachG(fn func(gp *g)) {
751 lock(&allglock)
752 for _, gp := range allgs {
753 fn(gp)
754 }
755 unlock(&allglock)
756 }
757
758
759
760
761
762 func forEachGRace(fn func(gp *g)) {
763 ptr, length := atomicAllG()
764 for i := uintptr(0); i < length; i++ {
765 gp := atomicAllGIndex(ptr, i)
766 fn(gp)
767 }
768 return
769 }
770
771 const (
772
773
774 _GoidCacheBatch = 16
775 )
776
777
778
779 func cpuinit(env string) {
780 cpu.Initialize(env)
781
782
783
784 switch GOARCH {
785 case "386", "amd64":
786 x86HasAVX = cpu.X86.HasAVX
787 x86HasFMA = cpu.X86.HasFMA
788 x86HasPOPCNT = cpu.X86.HasPOPCNT
789 x86HasSSE41 = cpu.X86.HasSSE41
790
791 case "arm":
792 armHasVFPv4 = cpu.ARM.HasVFPv4
793
794 case "arm64":
795 arm64HasATOMICS = cpu.ARM64.HasATOMICS
796
797 case "loong64":
798 loong64HasLAMCAS = cpu.Loong64.HasLAMCAS
799 loong64HasLAM_BH = cpu.Loong64.HasLAM_BH
800 loong64HasDBAR_HINTS = cpu.Loong64.HasDBAR_HINTS
801 loong64HasLSX = cpu.Loong64.HasLSX
802
803 case "riscv64":
804 riscv64HasV = cpu.RISCV64.HasV
805 riscv64HasZbb = cpu.RISCV64.HasZbb
806 }
807 }
808
809
810
811
812
813
814 func getGodebugEarly() (string, bool) {
815 const prefix = "GODEBUG="
816 var env string
817 switch GOOS {
818 case "aix", "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd", "illumos", "solaris", "linux":
819
820
821
822 n := int32(0)
823 for argv_index(argv, argc+1+n) != nil {
824 n++
825 }
826
827 for i := int32(0); i < n; i++ {
828 p := argv_index(argv, argc+1+i)
829 s := unsafe.String(p, findnull(p))
830
831 if stringslite.HasPrefix(s, prefix) {
832 env = gostringnocopy(p)[len(prefix):]
833 break
834 }
835 }
836 break
837
838 default:
839 return "", false
840 }
841 return env, true
842 }
843
844
845
846
847
848
849
850
851
852 func schedinit() {
853 lockInit(&sched.lock, lockRankSched)
854 lockInit(&sched.sysmonlock, lockRankSysmon)
855 lockInit(&sched.deferlock, lockRankDefer)
856 lockInit(&sched.waitingGLock, lockRankWaitingG)
857 lockInit(&deadlock, lockRankDeadlock)
858 lockInit(&paniclk, lockRankPanic)
859 lockInit(&allglock, lockRankAllg)
860 lockInit(&allpLock, lockRankAllp)
861 lockInit(&reflectOffs.lock, lockRankReflectOffs)
862 lockInit(&finlock, lockRankFin)
863 lockInit(&cpuprof.lock, lockRankCpuprof)
864 lockInit(&computeMaxProcsLock, lockRankComputeMaxProcs)
865 allocmLock.init(lockRankAllocmR, lockRankAllocmRInternal, lockRankAllocmW)
866 execLock.init(lockRankExecR, lockRankExecRInternal, lockRankExecW)
867 traceLockInit()
868
869
870
871 lockInit(&memstats.heapStats.noPLock, lockRankLeafRank)
872
873 lockVerifyMSize()
874
875 sched.midle.init(unsafe.Offsetof(m{}.idleNode))
876
877
878
879 gp := getg()
880 if raceenabled {
881 gp.racectx, raceprocctx0 = raceinit()
882 }
883
884 sched.maxmcount = 10000
885 crashFD.Store(^uintptr(0))
886
887
888 worldStopped()
889
890 godebug, parsedGodebug := getGodebugEarly()
891 if parsedGodebug {
892 parseRuntimeDebugVars(godebug)
893 }
894 ticks.init()
895 moduledataverify()
896 stackinit()
897 randinit()
898 mallocinit()
899 cpuinit(godebug)
900 maps.AlgInit()
901 mcommoninit(gp.m, -1)
902 modulesinit()
903 typelinksinit()
904 itabsinit()
905 stkobjinit()
906
907 sigsave(&gp.m.sigmask)
908 initSigmask = gp.m.sigmask
909
910 goargs()
911 goenvs()
912 secure()
913 checkfds()
914 if !parsedGodebug {
915
916
917 parseRuntimeDebugVars(gogetenv("GODEBUG"))
918 }
919 finishDebugVarsSetup()
920 gcinit()
921
922
923
924 gcrash.stack = stackalloc(16384)
925 gcrash.stackguard0 = gcrash.stack.lo + 1000
926 gcrash.stackguard1 = gcrash.stack.lo + 1000
927
928
929
930
931
932 if disableMemoryProfiling {
933 MemProfileRate = 0
934 }
935
936
937 mProfStackInit(gp.m)
938 defaultGOMAXPROCSInit()
939
940 lock(&sched.lock)
941 sched.lastpoll.Store(nanotime())
942 var procs int32
943 if n, err := strconv.ParseInt(gogetenv("GOMAXPROCS"), 10, 32); err == nil && n > 0 {
944 procs = int32(n)
945 sched.customGOMAXPROCS = true
946 } else {
947
948
949
950
951
952
953
954
955 procs = defaultGOMAXPROCS(numCPUStartup)
956 }
957 if procresize(procs) != nil {
958 throw("unknown runnable goroutine during bootstrap")
959 }
960 unlock(&sched.lock)
961
962
963 worldStarted()
964
965 if buildVersion == "" {
966
967
968 buildVersion = "unknown"
969 }
970 if len(modinfo) == 1 {
971
972
973 modinfo = ""
974 }
975 }
976
977 func dumpgstatus(gp *g) {
978 thisg := getg()
979 print("runtime: gp: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")
980 print("runtime: getg: g=", thisg, ", goid=", thisg.goid, ", g->atomicstatus=", readgstatus(thisg), "\n")
981 }
982
983
984 func checkmcount() {
985 assertLockHeld(&sched.lock)
986
987
988
989
990
991
992
993
994
995 count := mcount() - int32(extraMInUse.Load()) - int32(extraMLength.Load())
996 if count > sched.maxmcount {
997 print("runtime: program exceeds ", sched.maxmcount, "-thread limit\n")
998 throw("thread exhaustion")
999 }
1000 }
1001
1002
1003
1004
1005
1006 func mReserveID() int64 {
1007 assertLockHeld(&sched.lock)
1008
1009 if sched.mnext+1 < sched.mnext {
1010 throw("runtime: thread ID overflow")
1011 }
1012 id := sched.mnext
1013 sched.mnext++
1014 checkmcount()
1015 return id
1016 }
1017
1018
1019 func mcommoninit(mp *m, id int64) {
1020 gp := getg()
1021
1022
1023 if gp != gp.m.g0 {
1024 callers(1, mp.createstack[:])
1025 }
1026
1027 lock(&sched.lock)
1028
1029 if id >= 0 {
1030 mp.id = id
1031 } else {
1032 mp.id = mReserveID()
1033 }
1034
1035 mp.self = newMWeakPointer(mp)
1036
1037 mrandinit(mp)
1038
1039 mpreinit(mp)
1040 if mp.gsignal != nil {
1041 mp.gsignal.stackguard1 = mp.gsignal.stack.lo + stackGuard
1042 }
1043
1044
1045
1046 mp.alllink = allm
1047
1048
1049
1050 atomicstorep(unsafe.Pointer(&allm), unsafe.Pointer(mp))
1051 unlock(&sched.lock)
1052
1053
1054 if iscgo || GOOS == "solaris" || GOOS == "illumos" || GOOS == "windows" {
1055 mp.cgoCallers = new(cgoCallers)
1056 }
1057 mProfStackInit(mp)
1058 }
1059
1060
1061
1062
1063
1064 func mProfStackInit(mp *m) {
1065 if debug.profstackdepth == 0 {
1066
1067
1068 return
1069 }
1070 mp.profStack = makeProfStackFP()
1071 mp.mLockProfile.stack = makeProfStackFP()
1072 }
1073
1074
1075
1076
1077 func makeProfStackFP() []uintptr {
1078
1079
1080
1081
1082
1083
1084 return make([]uintptr, 1+maxSkip+debug.profstackdepth)
1085 }
1086
1087
1088
1089 func makeProfStack() []uintptr { return make([]uintptr, debug.profstackdepth) }
1090
1091
1092 func pprof_makeProfStack() []uintptr { return makeProfStack() }
1093
1094 func (mp *m) becomeSpinning() {
1095 mp.spinning = true
1096 sched.nmspinning.Add(1)
1097 sched.needspinning.Store(0)
1098 }
1099
1100
1101
1102
1103
1104
1105
1106
1107 func (mp *m) snapshotAllp() []*p {
1108 mp.allpSnapshot = allp
1109 return mp.allpSnapshot
1110 }
1111
1112
1113
1114
1115
1116
1117
1118 func (mp *m) clearAllpSnapshot() {
1119 mp.allpSnapshot = nil
1120 }
1121
1122 func (mp *m) hasCgoOnStack() bool {
1123 return mp.ncgo > 0 || mp.isextra
1124 }
1125
1126
1127
1128 const osHasLowResTimer = GOOS == "windows" || GOOS == "openbsd" || GOOS == "netbsd" || GOOS == "plan9"
1129
1130
1131 func ready(gp *g, traceskip int, next bool) {
1132 status := readgstatus(gp)
1133
1134
1135 mp := acquirem()
1136 if status&^_Gscan != _Gwaiting {
1137 dumpgstatus(gp)
1138 throw("bad g->status in ready")
1139 }
1140
1141
1142 trace := traceAcquire()
1143 casgstatus(gp, _Gwaiting, _Grunnable)
1144 if trace.ok() {
1145 trace.GoUnpark(gp, traceskip)
1146 traceRelease(trace)
1147 }
1148 runqput(mp.p.ptr(), gp, next)
1149 wakep()
1150 releasem(mp)
1151 }
1152
1153
1154
1155 const freezeStopWait = 0x7fffffff
1156
1157
1158
1159 var freezing atomic.Bool
1160
1161
1162
1163
1164 func freezetheworld() {
1165 freezing.Store(true)
1166 if debug.dontfreezetheworld > 0 {
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191 usleep(1000)
1192 return
1193 }
1194
1195
1196
1197
1198 for i := 0; i < 5; i++ {
1199
1200 sched.stopwait = freezeStopWait
1201 sched.gcwaiting.Store(true)
1202
1203 if !preemptall() {
1204 break
1205 }
1206 usleep(1000)
1207 }
1208
1209 usleep(1000)
1210 preemptall()
1211 usleep(1000)
1212 }
1213
1214
1215
1216
1217
1218 func readgstatus(gp *g) uint32 {
1219 return gp.atomicstatus.Load()
1220 }
1221
1222
1223
1224
1225
1226 func casfrom_Gscanstatus(gp *g, oldval, newval uint32) {
1227 success := false
1228
1229
1230 switch oldval {
1231 default:
1232 print("runtime: casfrom_Gscanstatus bad oldval gp=", gp, ", oldval=", hex(oldval), ", newval=", hex(newval), "\n")
1233 dumpgstatus(gp)
1234 throw("casfrom_Gscanstatus:top gp->status is not in scan state")
1235 case _Gscanrunnable,
1236 _Gscanwaiting,
1237 _Gscanrunning,
1238 _Gscansyscall,
1239 _Gscanleaked,
1240 _Gscanpreempted,
1241 _Gscandeadextra:
1242 if newval == oldval&^_Gscan {
1243 success = gp.atomicstatus.CompareAndSwap(oldval, newval)
1244 }
1245 }
1246 if !success {
1247 print("runtime: casfrom_Gscanstatus failed gp=", gp, ", oldval=", hex(oldval), ", newval=", hex(newval), "\n")
1248 dumpgstatus(gp)
1249 throw("casfrom_Gscanstatus: gp->status is not in scan state")
1250 }
1251 releaseLockRankAndM(lockRankGscan)
1252 }
1253
1254
1255
1256 func castogscanstatus(gp *g, oldval, newval uint32) bool {
1257 switch oldval {
1258 case _Grunnable,
1259 _Grunning,
1260 _Gwaiting,
1261 _Gleaked,
1262 _Gsyscall,
1263 _Gdeadextra:
1264 if newval == oldval|_Gscan {
1265 r := gp.atomicstatus.CompareAndSwap(oldval, newval)
1266 if r {
1267 acquireLockRankAndM(lockRankGscan)
1268 }
1269 return r
1270
1271 }
1272 }
1273 print("runtime: castogscanstatus oldval=", hex(oldval), " newval=", hex(newval), "\n")
1274 throw("bad oldval passed to castogscanstatus")
1275 return false
1276 }
1277
1278
1279
1280 var casgstatusAlwaysTrack = false
1281
1282
1283
1284
1285
1286
1287
1288 func casgstatus(gp *g, oldval, newval uint32) {
1289 if (oldval&_Gscan != 0) || (newval&_Gscan != 0) || oldval == newval {
1290 systemstack(func() {
1291
1292
1293 print("runtime: casgstatus: oldval=", hex(oldval), " newval=", hex(newval), "\n")
1294 throw("casgstatus: bad incoming values")
1295 })
1296 }
1297
1298 lockWithRankMayAcquire(nil, lockRankGscan)
1299
1300
1301 const yieldDelay = 5 * 1000
1302 var nextYield int64
1303
1304
1305
1306 for i := 0; !gp.atomicstatus.CompareAndSwap(oldval, newval); i++ {
1307 if oldval == _Gwaiting && gp.atomicstatus.Load() == _Grunnable {
1308 systemstack(func() {
1309
1310
1311 throw("casgstatus: waiting for Gwaiting but is Grunnable")
1312 })
1313 }
1314 if i == 0 {
1315 nextYield = nanotime() + yieldDelay
1316 }
1317 if nanotime() < nextYield {
1318 for x := 0; x < 10 && gp.atomicstatus.Load() != oldval; x++ {
1319 procyield(1)
1320 }
1321 } else {
1322 osyield()
1323 nextYield = nanotime() + yieldDelay/2
1324 }
1325 }
1326
1327 if gp.bubble != nil {
1328 systemstack(func() {
1329 gp.bubble.changegstatus(gp, oldval, newval)
1330 })
1331 }
1332
1333 if (oldval == _Grunning || oldval == _Gsyscall) && (newval != _Grunning && newval != _Gsyscall) {
1334
1335
1336 if casgstatusAlwaysTrack || gp.trackingSeq%gTrackingPeriod == 0 {
1337 gp.tracking = true
1338 }
1339 gp.trackingSeq++
1340 }
1341 if !gp.tracking {
1342 return
1343 }
1344
1345
1346
1347
1348
1349
1350 switch oldval {
1351 case _Grunnable:
1352
1353
1354
1355 now := nanotime()
1356 gp.runnableTime += now - gp.trackingStamp
1357 gp.trackingStamp = 0
1358 case _Gwaiting:
1359 if !gp.waitreason.isMutexWait() {
1360
1361 break
1362 }
1363
1364
1365
1366
1367
1368 now := nanotime()
1369 sched.totalMutexWaitTime.Add((now - gp.trackingStamp) * gTrackingPeriod)
1370 gp.trackingStamp = 0
1371 }
1372 switch newval {
1373 case _Gwaiting:
1374 if !gp.waitreason.isMutexWait() {
1375
1376 break
1377 }
1378
1379 now := nanotime()
1380 gp.trackingStamp = now
1381 case _Grunnable:
1382
1383
1384 now := nanotime()
1385 gp.trackingStamp = now
1386 case _Grunning:
1387
1388
1389
1390 gp.tracking = false
1391 sched.timeToRun.record(gp.runnableTime)
1392 gp.runnableTime = 0
1393 }
1394 }
1395
1396
1397
1398
1399 func casGToWaiting(gp *g, old uint32, reason waitReason) {
1400
1401 gp.waitreason = reason
1402 casgstatus(gp, old, _Gwaiting)
1403 }
1404
1405
1406
1407
1408
1409
1410
1411
1412 func casGToWaitingForSuspendG(gp *g, old uint32, reason waitReason) {
1413 if !reason.isWaitingForSuspendG() {
1414 throw("casGToWaitingForSuspendG with non-isWaitingForSuspendG wait reason")
1415 }
1416 casGToWaiting(gp, old, reason)
1417 }
1418
1419
1420
1421
1422
1423 func casGToPreemptScan(gp *g, old, new uint32) {
1424 if old != _Grunning || new != _Gscan|_Gpreempted {
1425 throw("bad g transition")
1426 }
1427 acquireLockRankAndM(lockRankGscan)
1428 for !gp.atomicstatus.CompareAndSwap(_Grunning, _Gscan|_Gpreempted) {
1429 }
1430
1431
1432
1433
1434
1435
1436 }
1437
1438
1439
1440
1441 func casGFromPreempted(gp *g, old, new uint32) bool {
1442 if old != _Gpreempted || new != _Gwaiting {
1443 throw("bad g transition")
1444 }
1445 gp.waitreason = waitReasonPreempted
1446 if !gp.atomicstatus.CompareAndSwap(_Gpreempted, _Gwaiting) {
1447 return false
1448 }
1449 if bubble := gp.bubble; bubble != nil {
1450 bubble.changegstatus(gp, _Gpreempted, _Gwaiting)
1451 }
1452 return true
1453 }
1454
1455
1456 type stwReason uint8
1457
1458
1459
1460
1461 const (
1462 stwUnknown stwReason = iota
1463 stwGCMarkTerm
1464 stwGCSweepTerm
1465 stwWriteHeapDump
1466 stwGoroutineProfile
1467 stwGoroutineProfileCleanup
1468 stwAllGoroutinesStack
1469 stwReadMemStats
1470 stwAllThreadsSyscall
1471 stwGOMAXPROCS
1472 stwStartTrace
1473 stwStopTrace
1474 stwForTestCountPagesInUse
1475 stwForTestReadMetricsSlow
1476 stwForTestReadMemStatsSlow
1477 stwForTestPageCachePagesLeaked
1478 stwForTestResetDebugLog
1479 )
1480
1481 func (r stwReason) String() string {
1482 return stwReasonStrings[r]
1483 }
1484
1485 func (r stwReason) isGC() bool {
1486 return r == stwGCMarkTerm || r == stwGCSweepTerm
1487 }
1488
1489
1490
1491
1492 var stwReasonStrings = [...]string{
1493 stwUnknown: "unknown",
1494 stwGCMarkTerm: "GC mark termination",
1495 stwGCSweepTerm: "GC sweep termination",
1496 stwWriteHeapDump: "write heap dump",
1497 stwGoroutineProfile: "goroutine profile",
1498 stwGoroutineProfileCleanup: "goroutine profile cleanup",
1499 stwAllGoroutinesStack: "all goroutines stack trace",
1500 stwReadMemStats: "read mem stats",
1501 stwAllThreadsSyscall: "AllThreadsSyscall",
1502 stwGOMAXPROCS: "GOMAXPROCS",
1503 stwStartTrace: "start trace",
1504 stwStopTrace: "stop trace",
1505 stwForTestCountPagesInUse: "CountPagesInUse (test)",
1506 stwForTestReadMetricsSlow: "ReadMetricsSlow (test)",
1507 stwForTestReadMemStatsSlow: "ReadMemStatsSlow (test)",
1508 stwForTestPageCachePagesLeaked: "PageCachePagesLeaked (test)",
1509 stwForTestResetDebugLog: "ResetDebugLog (test)",
1510 }
1511
1512
1513
1514 type worldStop struct {
1515 reason stwReason
1516 startedStopping int64
1517 finishedStopping int64
1518 stoppingCPUTime int64
1519 }
1520
1521
1522
1523
1524 var stopTheWorldContext worldStop
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543 func stopTheWorld(reason stwReason) worldStop {
1544 semacquire(&worldsema)
1545 gp := getg()
1546 gp.m.preemptoff = reason.String()
1547 systemstack(func() {
1548 stopTheWorldContext = stopTheWorldWithSema(reason)
1549 })
1550 return stopTheWorldContext
1551 }
1552
1553
1554
1555
1556 func startTheWorld(w worldStop) {
1557 systemstack(func() { startTheWorldWithSema(0, w) })
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574 mp := acquirem()
1575 mp.preemptoff = ""
1576 semrelease1(&worldsema, true, 0)
1577 releasem(mp)
1578 }
1579
1580
1581
1582
1583 func stopTheWorldGC(reason stwReason) worldStop {
1584 semacquire(&gcsema)
1585 return stopTheWorld(reason)
1586 }
1587
1588
1589
1590
1591 func startTheWorldGC(w worldStop) {
1592 startTheWorld(w)
1593 semrelease(&gcsema)
1594 }
1595
1596
1597 var worldsema uint32 = 1
1598
1599
1600
1601
1602
1603
1604
1605 var gcsema uint32 = 1
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639 func stopTheWorldWithSema(reason stwReason) worldStop {
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652 casGToWaitingForSuspendG(getg().m.curg, _Grunning, waitReasonStoppingTheWorld)
1653
1654 trace := traceAcquire()
1655 if trace.ok() {
1656 trace.STWStart(reason)
1657 traceRelease(trace)
1658 }
1659 gp := getg()
1660
1661
1662
1663 if gp.m.locks > 0 {
1664 throw("stopTheWorld: holding locks")
1665 }
1666
1667 lock(&sched.lock)
1668 start := nanotime()
1669 sched.stopwait = gomaxprocs
1670 sched.gcwaiting.Store(true)
1671
1672
1673 gp.m.p.ptr().status = _Pgcstop
1674 gp.m.p.ptr().gcStopTime = start
1675 sched.stopwait--
1676
1677
1678 for _, pp := range allp {
1679 if thread, ok := setBlockOnExitSyscall(pp); ok {
1680 thread.gcstopP()
1681 thread.resume()
1682 }
1683 }
1684
1685
1686 now := nanotime()
1687 for {
1688 pp, _ := pidleget(now)
1689 if pp == nil {
1690 break
1691 }
1692 pp.status = _Pgcstop
1693 pp.gcStopTime = nanotime()
1694 sched.stopwait--
1695 }
1696 wait := sched.stopwait > 0
1697 unlock(&sched.lock)
1698
1699
1700 if wait {
1701 preemptall()
1702 stealRunnextWake()
1703 for {
1704
1705 if notetsleep(&sched.stopnote, 100*1000) {
1706 noteclear(&sched.stopnote)
1707 break
1708 }
1709 preemptall()
1710 }
1711 }
1712
1713 finish := nanotime()
1714 startTime := finish - start
1715 if reason.isGC() {
1716 sched.stwStoppingTimeGC.record(startTime)
1717 } else {
1718 sched.stwStoppingTimeOther.record(startTime)
1719 }
1720
1721
1722
1723
1724
1725 stoppingCPUTime := int64(0)
1726 bad := ""
1727 if sched.stopwait != 0 {
1728 bad = "stopTheWorld: not stopped (stopwait != 0)"
1729 } else {
1730 for _, pp := range allp {
1731 if pp.status != _Pgcstop {
1732 bad = "stopTheWorld: not stopped (status != _Pgcstop)"
1733 }
1734 if pp.gcStopTime == 0 && bad == "" {
1735 bad = "stopTheWorld: broken CPU time accounting"
1736 }
1737 stoppingCPUTime += finish - pp.gcStopTime
1738 pp.gcStopTime = 0
1739 }
1740 }
1741 if freezing.Load() {
1742
1743
1744
1745
1746 lock(&deadlock)
1747 lock(&deadlock)
1748 }
1749 if bad != "" {
1750 throw(bad)
1751 }
1752
1753 worldStopped()
1754
1755
1756 casgstatus(getg().m.curg, _Gwaiting, _Grunning)
1757
1758 return worldStop{
1759 reason: reason,
1760 startedStopping: start,
1761 finishedStopping: finish,
1762 stoppingCPUTime: stoppingCPUTime,
1763 }
1764 }
1765
1766
1767
1768
1769
1770
1771
1772 func startTheWorldWithSema(now int64, w worldStop) int64 {
1773 assertWorldStopped()
1774
1775 mp := acquirem()
1776 if netpollinited() {
1777 list, delta := netpoll(0)
1778 injectglist(&list)
1779 netpollAdjustWaiters(delta)
1780 }
1781 lock(&sched.lock)
1782
1783 procs := gomaxprocs
1784 if newprocs != 0 {
1785 procs = newprocs
1786 newprocs = 0
1787 }
1788 p1 := procresize(procs)
1789 sched.gcwaiting.Store(false)
1790 if sched.sysmonwait.Load() {
1791 sched.sysmonwait.Store(false)
1792 notewakeup(&sched.sysmonnote)
1793 }
1794 unlock(&sched.lock)
1795
1796 worldStarted()
1797
1798 for p1 != nil {
1799 p := p1
1800 p1 = p1.link.ptr()
1801 if p.m != 0 {
1802 mp := p.m.ptr()
1803 p.m = 0
1804 if mp.nextp != 0 {
1805 throw("startTheWorld: inconsistent mp->nextp")
1806 }
1807 mp.nextp.set(p)
1808 notewakeup(&mp.park)
1809 } else {
1810
1811 newm(nil, p, -1)
1812 }
1813 }
1814
1815
1816 if now == 0 {
1817 now = nanotime()
1818 }
1819 totalTime := now - w.startedStopping
1820 if w.reason.isGC() {
1821 sched.stwTotalTimeGC.record(totalTime)
1822 } else {
1823 sched.stwTotalTimeOther.record(totalTime)
1824 }
1825 trace := traceAcquire()
1826 if trace.ok() {
1827 trace.STWDone()
1828 traceRelease(trace)
1829 }
1830
1831
1832
1833
1834 wakep()
1835
1836 releasem(mp)
1837
1838 return now
1839 }
1840
1841
1842
1843 func usesLibcall() bool {
1844 switch GOOS {
1845 case "aix", "darwin", "illumos", "ios", "openbsd", "solaris", "windows":
1846 return true
1847 }
1848 return false
1849 }
1850
1851
1852
1853 func mStackIsSystemAllocated() bool {
1854 switch GOOS {
1855 case "aix", "darwin", "plan9", "illumos", "ios", "openbsd", "solaris", "windows":
1856 return true
1857 }
1858 return false
1859 }
1860
1861
1862
1863 func mstart()
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874 func mstart0() {
1875 gp := getg()
1876
1877 osStack := gp.stack.lo == 0
1878 if osStack {
1879
1880
1881
1882
1883
1884
1885
1886
1887 size := gp.stack.hi
1888 if size == 0 {
1889 size = 16384 * sys.StackGuardMultiplier
1890 }
1891 gp.stack.hi = uintptr(noescape(unsafe.Pointer(&size)))
1892 gp.stack.lo = gp.stack.hi - size + 1024
1893 }
1894
1895
1896 gp.stackguard0 = gp.stack.lo + stackGuard
1897
1898
1899 gp.stackguard1 = gp.stackguard0
1900 mstart1()
1901
1902
1903 if mStackIsSystemAllocated() {
1904
1905
1906
1907 osStack = true
1908 }
1909 mexit(osStack)
1910 }
1911
1912
1913
1914
1915
1916 func mstart1() {
1917 gp := getg()
1918
1919 if gp != gp.m.g0 {
1920 throw("bad runtime·mstart")
1921 }
1922
1923
1924
1925
1926
1927
1928
1929 gp.sched.g = guintptr(unsafe.Pointer(gp))
1930 gp.sched.pc = sys.GetCallerPC()
1931 gp.sched.sp = sys.GetCallerSP()
1932 gp.sched.bp = getcallerfp()
1933
1934 asminit()
1935 minit()
1936
1937
1938
1939 if gp.m == &m0 {
1940 mstartm0()
1941 }
1942
1943 if debug.dataindependenttiming == 1 {
1944 sys.EnableDIT()
1945 }
1946
1947 if fn := gp.m.mstartfn; fn != nil {
1948 fn()
1949 }
1950
1951 if gp.m != &m0 {
1952 acquirep(gp.m.nextp.ptr())
1953 gp.m.nextp = 0
1954 }
1955 schedule()
1956 }
1957
1958
1959
1960
1961
1962
1963
1964 func mstartm0() {
1965
1966
1967
1968 if (iscgo || GOOS == "windows") && !cgoHasExtraM {
1969 cgoHasExtraM = true
1970 newextram()
1971 }
1972 initsig(false)
1973 }
1974
1975
1976
1977
1978 func mPark() {
1979 gp := getg()
1980
1981
1982 if goexperiment.RuntimeSecret {
1983 eraseSecretsSignalStk()
1984 }
1985 notesleep(&gp.m.park)
1986 noteclear(&gp.m.park)
1987 }
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999 func mexit(osStack bool) {
2000 mp := getg().m
2001
2002 if mp == &m0 {
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014 handoffp(releasep())
2015 lock(&sched.lock)
2016 sched.nmfreed++
2017 checkdead()
2018 unlock(&sched.lock)
2019 mPark()
2020 throw("locked m0 woke up")
2021 }
2022
2023 sigblock(true)
2024 unminit()
2025
2026
2027 if mp.gsignal != nil {
2028 stackfree(mp.gsignal.stack)
2029 if valgrindenabled {
2030 valgrindDeregisterStack(mp.gsignal)
2031 }
2032
2033
2034
2035
2036 mp.gsignal = nil
2037 }
2038
2039
2040 vgetrandomDestroy(mp)
2041
2042
2043
2044 mp.self.clear()
2045
2046
2047 lock(&sched.lock)
2048 for pprev := &allm; *pprev != nil; pprev = &(*pprev).alllink {
2049 if *pprev == mp {
2050 *pprev = mp.alllink
2051 goto found
2052 }
2053 }
2054 throw("m not found in allm")
2055 found:
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070 mp.freeWait.Store(freeMWait)
2071 mp.freelink = sched.freem
2072 sched.freem = mp
2073 unlock(&sched.lock)
2074
2075 atomic.Xadd64(&ncgocall, int64(mp.ncgocall))
2076 sched.totalRuntimeLockWaitTime.Add(mp.mLockProfile.waitTime.Load())
2077
2078
2079 handoffp(releasep())
2080
2081
2082
2083
2084
2085 lock(&sched.lock)
2086 sched.nmfreed++
2087 checkdead()
2088 unlock(&sched.lock)
2089
2090 if GOOS == "darwin" || GOOS == "ios" {
2091
2092
2093 if mp.signalPending.Load() != 0 {
2094 pendingPreemptSignals.Add(-1)
2095 }
2096 }
2097
2098
2099
2100 mdestroy(mp)
2101
2102 if osStack {
2103
2104 mp.freeWait.Store(freeMRef)
2105
2106
2107
2108 return
2109 }
2110
2111
2112
2113
2114
2115 exitThread(&mp.freeWait)
2116 }
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128 func forEachP(reason waitReason, fn func(*p)) {
2129 systemstack(func() {
2130 gp := getg().m.curg
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142 casGToWaitingForSuspendG(gp, _Grunning, reason)
2143 forEachPInternal(fn)
2144 casgstatus(gp, _Gwaiting, _Grunning)
2145 })
2146 }
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157 func forEachPInternal(fn func(*p)) {
2158 if atomic.Load(&worldsema) != 0 {
2159
2160 throw("worldsema not held")
2161 }
2162
2163 mp := acquirem()
2164 pp := getg().m.p.ptr()
2165
2166 lock(&sched.lock)
2167 if sched.safePointWait != 0 {
2168 throw("forEachP: sched.safePointWait != 0")
2169 }
2170 sched.safePointWait = gomaxprocs - 1
2171 sched.safePointFn = fn
2172
2173
2174 for _, p2 := range allp {
2175 if p2 != pp {
2176 atomic.Store(&p2.runSafePointFn, 1)
2177 }
2178 }
2179
2180
2181
2182
2183
2184
2185
2186 for p := sched.pidle.ptr(); p != nil; p = p.link.ptr() {
2187 if atomic.Cas(&p.runSafePointFn, 1, 0) {
2188 fn(p)
2189 sched.safePointWait--
2190 }
2191 }
2192
2193 wait := sched.safePointWait > 0
2194 unlock(&sched.lock)
2195
2196 if wait {
2197 preemptall()
2198 }
2199
2200
2201 fn(pp)
2202
2203
2204
2205 for _, p2 := range allp {
2206 if atomic.Load(&p2.runSafePointFn) != 1 {
2207
2208 continue
2209 }
2210 if thread, ok := setBlockOnExitSyscall(p2); ok {
2211 thread.takeP()
2212 thread.resume()
2213 handoffp(p2)
2214 }
2215 }
2216
2217
2218 if wait {
2219 for {
2220
2221
2222
2223
2224 if notetsleep(&sched.safePointNote, 100*1000) {
2225 noteclear(&sched.safePointNote)
2226 break
2227 }
2228 preemptall()
2229 }
2230 }
2231 if sched.safePointWait != 0 {
2232 throw("forEachP: not done")
2233 }
2234 for _, p2 := range allp {
2235 if p2.runSafePointFn != 0 {
2236 throw("forEachP: P did not run fn")
2237 }
2238 }
2239
2240 lock(&sched.lock)
2241 sched.safePointFn = nil
2242 unlock(&sched.lock)
2243 releasem(mp)
2244 }
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257 func runSafePointFn() {
2258 p := getg().m.p.ptr()
2259
2260
2261
2262 if !atomic.Cas(&p.runSafePointFn, 1, 0) {
2263 return
2264 }
2265 sched.safePointFn(p)
2266 lock(&sched.lock)
2267 sched.safePointWait--
2268 if sched.safePointWait == 0 {
2269 notewakeup(&sched.safePointNote)
2270 }
2271 unlock(&sched.lock)
2272 }
2273
2274
2275
2276
2277 var cgoThreadStart unsafe.Pointer
2278
2279 type cgothreadstart struct {
2280 g guintptr
2281 tls *uint64
2282 fn unsafe.Pointer
2283 }
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294 func allocm(pp *p, fn func(), id int64) *m {
2295 allocmLock.rlock()
2296
2297
2298
2299
2300 acquirem()
2301
2302 gp := getg()
2303 if gp.m.p == 0 {
2304 acquirep(pp)
2305 }
2306
2307
2308
2309 if sched.freem != nil {
2310 lock(&sched.lock)
2311 var newList *m
2312 for freem := sched.freem; freem != nil; {
2313
2314 wait := freem.freeWait.Load()
2315 if wait == freeMWait {
2316 next := freem.freelink
2317 freem.freelink = newList
2318 newList = freem
2319 freem = next
2320 continue
2321 }
2322
2323
2324
2325 if traceEnabled() || traceShuttingDown() {
2326 traceThreadDestroy(freem)
2327 }
2328
2329
2330
2331 if wait == freeMStack {
2332
2333
2334
2335 systemstack(func() {
2336 stackfree(freem.g0.stack)
2337 if valgrindenabled {
2338 valgrindDeregisterStack(freem.g0)
2339 }
2340 })
2341 }
2342 freem = freem.freelink
2343 }
2344 sched.freem = newList
2345 unlock(&sched.lock)
2346 }
2347
2348 mp := &new(mPadded).m
2349 mp.mstartfn = fn
2350 mcommoninit(mp, id)
2351
2352
2353
2354 if iscgo || mStackIsSystemAllocated() {
2355 mp.g0 = malg(-1)
2356 } else {
2357 mp.g0 = malg(16384 * sys.StackGuardMultiplier)
2358 }
2359 mp.g0.m = mp
2360
2361 if pp == gp.m.p.ptr() {
2362 releasep()
2363 }
2364
2365 releasem(gp.m)
2366 allocmLock.runlock()
2367 return mp
2368 }
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409 func needm(signal bool) {
2410 if (iscgo || GOOS == "windows") && !cgoHasExtraM {
2411
2412
2413
2414
2415
2416
2417 writeErrStr("fatal error: cgo callback before cgo call\n")
2418 exit(1)
2419 }
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429 var sigmask sigset
2430 sigsave(&sigmask)
2431 sigblock(false)
2432
2433
2434
2435
2436 mp, last := getExtraM()
2437
2438
2439
2440
2441
2442
2443
2444
2445 mp.needextram = last
2446
2447
2448 mp.sigmask = sigmask
2449
2450
2451
2452 setg(mp.g0)
2453 sp := sys.GetCallerSP()
2454 callbackUpdateSystemStack(mp, sp, signal)
2455
2456
2457
2458
2459 mp.isExtraInC = false
2460
2461
2462 asminit()
2463 minit()
2464
2465
2466
2467
2468
2469
2470 var trace traceLocker
2471 if !signal {
2472 trace = traceAcquire()
2473 }
2474
2475
2476 casgstatus(mp.curg, _Gdeadextra, _Gsyscall)
2477 sched.ngsys.Add(-1)
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487 addGSyscallNoP(mp)
2488
2489 if !signal {
2490 if trace.ok() {
2491 trace.GoCreateSyscall(mp.curg)
2492 traceRelease(trace)
2493 }
2494 }
2495 mp.isExtraInSig = signal
2496 }
2497
2498
2499
2500
2501 func needAndBindM() {
2502 needm(false)
2503
2504 if _cgo_pthread_key_created != nil && *(*uintptr)(_cgo_pthread_key_created) != 0 {
2505 cgoBindM()
2506 }
2507 }
2508
2509
2510
2511
2512 func newextram() {
2513 c := extraMWaiters.Swap(0)
2514 if c > 0 {
2515 for i := uint32(0); i < c; i++ {
2516 oneNewExtraM()
2517 }
2518 } else if extraMLength.Load() == 0 {
2519
2520 oneNewExtraM()
2521 }
2522 }
2523
2524
2525 func oneNewExtraM() {
2526
2527
2528
2529
2530
2531 mp := allocm(nil, nil, -1)
2532 gp := malg(4096)
2533 gp.sched.pc = abi.FuncPCABI0(goexit) + sys.PCQuantum
2534 gp.sched.sp = gp.stack.hi
2535 gp.sched.sp -= 4 * goarch.PtrSize
2536 gp.sched.lr = 0
2537 gp.sched.g = guintptr(unsafe.Pointer(gp))
2538 gp.syscallpc = gp.sched.pc
2539 gp.syscallsp = gp.sched.sp
2540 gp.stktopsp = gp.sched.sp
2541
2542
2543
2544 casgstatus(gp, _Gidle, _Gdeadextra)
2545 gp.m = mp
2546 mp.curg = gp
2547 mp.isextra = true
2548
2549 mp.isExtraInC = true
2550 mp.lockedInt++
2551 mp.lockedg.set(gp)
2552 gp.lockedm.set(mp)
2553 gp.goid = sched.goidgen.Add(1)
2554 if raceenabled {
2555 gp.racectx = racegostart(abi.FuncPCABIInternal(newextram) + sys.PCQuantum)
2556 }
2557
2558 allgadd(gp)
2559
2560
2561
2562
2563
2564 sched.ngsys.Add(1)
2565
2566
2567 addExtraM(mp)
2568 }
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603 func dropm() {
2604
2605
2606
2607 mp := getg().m
2608
2609
2610
2611
2612
2613 var trace traceLocker
2614 if !mp.isExtraInSig {
2615 trace = traceAcquire()
2616 }
2617
2618
2619 casgstatus(mp.curg, _Gsyscall, _Gdeadextra)
2620 mp.curg.preemptStop = false
2621 sched.ngsys.Add(1)
2622 decGSyscallNoP(mp)
2623
2624 if !mp.isExtraInSig {
2625 if trace.ok() {
2626 trace.GoDestroySyscall()
2627 traceRelease(trace)
2628 }
2629 }
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644 mp.syscalltick--
2645
2646
2647
2648 mp.curg.trace.reset()
2649
2650
2651
2652
2653 if traceEnabled() || traceShuttingDown() {
2654
2655
2656
2657
2658
2659
2660
2661 lock(&sched.lock)
2662 traceThreadDestroy(mp)
2663 unlock(&sched.lock)
2664 }
2665 mp.isExtraInSig = false
2666
2667
2668
2669
2670
2671 sigmask := mp.sigmask
2672 sigblock(false)
2673 unminit()
2674
2675 setg(nil)
2676
2677
2678
2679 g0 := mp.g0
2680 g0.stack.hi = 0
2681 g0.stack.lo = 0
2682 g0.stackguard0 = 0
2683 g0.stackguard1 = 0
2684 mp.g0StackAccurate = false
2685
2686 putExtraM(mp)
2687
2688 msigrestore(sigmask)
2689 }
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711 func cgoBindM() {
2712 if GOOS == "windows" || GOOS == "plan9" {
2713 fatal("bindm in unexpected GOOS")
2714 }
2715 g := getg()
2716 if g.m.g0 != g {
2717 fatal("the current g is not g0")
2718 }
2719 if _cgo_bindm != nil {
2720 asmcgocall(_cgo_bindm, unsafe.Pointer(g))
2721 }
2722 }
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735 func getm() uintptr {
2736 return uintptr(unsafe.Pointer(getg().m))
2737 }
2738
2739 var (
2740
2741
2742
2743
2744
2745
2746 extraM atomic.Uintptr
2747
2748 extraMLength atomic.Uint32
2749
2750 extraMWaiters atomic.Uint32
2751
2752
2753 extraMInUse atomic.Uint32
2754 )
2755
2756
2757
2758
2759
2760
2761
2762
2763 func lockextra(nilokay bool) *m {
2764 const locked = 1
2765
2766 incr := false
2767 for {
2768 old := extraM.Load()
2769 if old == locked {
2770 osyield_no_g()
2771 continue
2772 }
2773 if old == 0 && !nilokay {
2774 if !incr {
2775
2776
2777
2778 extraMWaiters.Add(1)
2779 incr = true
2780 }
2781 usleep_no_g(1)
2782 continue
2783 }
2784 if extraM.CompareAndSwap(old, locked) {
2785 return (*m)(unsafe.Pointer(old))
2786 }
2787 osyield_no_g()
2788 continue
2789 }
2790 }
2791
2792
2793 func unlockextra(mp *m, delta int32) {
2794 extraMLength.Add(delta)
2795 extraM.Store(uintptr(unsafe.Pointer(mp)))
2796 }
2797
2798
2799
2800
2801
2802
2803
2804
2805 func getExtraM() (mp *m, last bool) {
2806 mp = lockextra(false)
2807 extraMInUse.Add(1)
2808 unlockextra(mp.schedlink.ptr(), -1)
2809 return mp, mp.schedlink.ptr() == nil
2810 }
2811
2812
2813
2814
2815
2816 func putExtraM(mp *m) {
2817 extraMInUse.Add(-1)
2818 addExtraM(mp)
2819 }
2820
2821
2822
2823
2824 func addExtraM(mp *m) {
2825 mnext := lockextra(true)
2826 mp.schedlink.set(mnext)
2827 unlockextra(mp, 1)
2828 }
2829
2830 var (
2831
2832
2833
2834 allocmLock rwmutex
2835
2836
2837
2838
2839 execLock rwmutex
2840 )
2841
2842
2843
2844 const (
2845 failthreadcreate = "runtime: failed to create new OS thread\n"
2846 failallocatestack = "runtime: failed to allocate stack for the new OS thread\n"
2847 )
2848
2849
2850
2851
2852 var newmHandoff struct {
2853 lock mutex
2854
2855
2856
2857 newm muintptr
2858
2859
2860
2861 waiting bool
2862 wake note
2863
2864
2865
2866
2867 haveTemplateThread uint32
2868 }
2869
2870
2871
2872
2873
2874
2875
2876
2877 func newm(fn func(), pp *p, id int64) {
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888 acquirem()
2889
2890 mp := allocm(pp, fn, id)
2891 mp.nextp.set(pp)
2892 mp.sigmask = initSigmask
2893 if gp := getg(); gp != nil && gp.m != nil && (gp.m.lockedExt != 0 || gp.m.incgo) && GOOS != "plan9" {
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905 lock(&newmHandoff.lock)
2906 if newmHandoff.haveTemplateThread == 0 {
2907 throw("on a locked thread with no template thread")
2908 }
2909 mp.schedlink = newmHandoff.newm
2910 newmHandoff.newm.set(mp)
2911 if newmHandoff.waiting {
2912 newmHandoff.waiting = false
2913 notewakeup(&newmHandoff.wake)
2914 }
2915 unlock(&newmHandoff.lock)
2916
2917
2918
2919 releasem(getg().m)
2920 return
2921 }
2922 newm1(mp)
2923 releasem(getg().m)
2924 }
2925
2926 func newm1(mp *m) {
2927 if iscgo && _cgo_thread_start != nil {
2928 var ts cgothreadstart
2929 ts.g.set(mp.g0)
2930 ts.tls = (*uint64)(unsafe.Pointer(&mp.tls[0]))
2931 ts.fn = unsafe.Pointer(abi.FuncPCABI0(mstart))
2932 if msanenabled {
2933 msanwrite(unsafe.Pointer(&ts), unsafe.Sizeof(ts))
2934 }
2935 if asanenabled {
2936 asanwrite(unsafe.Pointer(&ts), unsafe.Sizeof(ts))
2937 }
2938 execLock.rlock()
2939 asmcgocall(_cgo_thread_start, unsafe.Pointer(&ts))
2940 execLock.runlock()
2941 return
2942 }
2943 execLock.rlock()
2944 newosproc(mp)
2945 execLock.runlock()
2946 }
2947
2948
2949
2950
2951
2952 func startTemplateThread() {
2953 if GOARCH == "wasm" {
2954 return
2955 }
2956
2957
2958
2959 mp := acquirem()
2960 if !atomic.Cas(&newmHandoff.haveTemplateThread, 0, 1) {
2961 releasem(mp)
2962 return
2963 }
2964 newm(templateThread, nil, -1)
2965 releasem(mp)
2966 }
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980 func templateThread() {
2981 lock(&sched.lock)
2982 sched.nmsys++
2983 checkdead()
2984 unlock(&sched.lock)
2985
2986 for {
2987 lock(&newmHandoff.lock)
2988 for newmHandoff.newm != 0 {
2989 newm := newmHandoff.newm.ptr()
2990 newmHandoff.newm = 0
2991 unlock(&newmHandoff.lock)
2992 for newm != nil {
2993 next := newm.schedlink.ptr()
2994 newm.schedlink = 0
2995 newm1(newm)
2996 newm = next
2997 }
2998 lock(&newmHandoff.lock)
2999 }
3000 newmHandoff.waiting = true
3001 noteclear(&newmHandoff.wake)
3002 unlock(&newmHandoff.lock)
3003 notesleep(&newmHandoff.wake)
3004 }
3005 }
3006
3007
3008
3009 func stopm() {
3010 gp := getg()
3011
3012 if gp.m.locks != 0 {
3013 throw("stopm holding locks")
3014 }
3015 if gp.m.p != 0 {
3016 throw("stopm holding p")
3017 }
3018 if gp.m.spinning {
3019 throw("stopm spinning")
3020 }
3021
3022 lock(&sched.lock)
3023 mput(gp.m)
3024 unlock(&sched.lock)
3025 mPark()
3026 acquirep(gp.m.nextp.ptr())
3027 gp.m.nextp = 0
3028 }
3029
3030 func mspinning() {
3031
3032 getg().m.spinning = true
3033 }
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052 func startm(pp *p, spinning, lockheld bool) {
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069 mp := acquirem()
3070 if !lockheld {
3071 lock(&sched.lock)
3072 }
3073 if pp == nil {
3074 if spinning {
3075
3076
3077
3078 throw("startm: P required for spinning=true")
3079 }
3080 pp, _ = pidleget(0)
3081 if pp == nil {
3082 if !lockheld {
3083 unlock(&sched.lock)
3084 }
3085 releasem(mp)
3086 return
3087 }
3088 }
3089 nmp := mget()
3090 if nmp == nil {
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105 id := mReserveID()
3106 unlock(&sched.lock)
3107
3108 var fn func()
3109 if spinning {
3110
3111 fn = mspinning
3112 }
3113 newm(fn, pp, id)
3114
3115 if lockheld {
3116 lock(&sched.lock)
3117 }
3118
3119
3120 releasem(mp)
3121 return
3122 }
3123 if !lockheld {
3124 unlock(&sched.lock)
3125 }
3126 if nmp.spinning {
3127 throw("startm: m is spinning")
3128 }
3129 if nmp.nextp != 0 {
3130 throw("startm: m has p")
3131 }
3132 if spinning && !runqempty(pp) {
3133 throw("startm: p has runnable gs")
3134 }
3135
3136 nmp.spinning = spinning
3137 nmp.nextp.set(pp)
3138 notewakeup(&nmp.park)
3139
3140
3141 releasem(mp)
3142 }
3143
3144
3145
3146
3147
3148 func handoffp(pp *p) {
3149
3150
3151
3152
3153 if !runqempty(pp) || !sched.runq.empty() {
3154 startm(pp, false, false)
3155 return
3156 }
3157
3158 if (traceEnabled() || traceShuttingDown()) && traceReaderAvailable() != nil {
3159 startm(pp, false, false)
3160 return
3161 }
3162
3163 if gcBlackenEnabled != 0 && gcShouldScheduleWorker(pp) {
3164 startm(pp, false, false)
3165 return
3166 }
3167
3168
3169 if sched.nmspinning.Load()+sched.npidle.Load() == 0 && sched.nmspinning.CompareAndSwap(0, 1) {
3170 sched.needspinning.Store(0)
3171 startm(pp, true, false)
3172 return
3173 }
3174 lock(&sched.lock)
3175 if sched.gcwaiting.Load() {
3176 pp.status = _Pgcstop
3177 pp.gcStopTime = nanotime()
3178 sched.stopwait--
3179 if sched.stopwait == 0 {
3180 notewakeup(&sched.stopnote)
3181 }
3182 unlock(&sched.lock)
3183 return
3184 }
3185 if pp.runSafePointFn != 0 && atomic.Cas(&pp.runSafePointFn, 1, 0) {
3186 sched.safePointFn(pp)
3187 sched.safePointWait--
3188 if sched.safePointWait == 0 {
3189 notewakeup(&sched.safePointNote)
3190 }
3191 }
3192 if !sched.runq.empty() {
3193 unlock(&sched.lock)
3194 startm(pp, false, false)
3195 return
3196 }
3197
3198
3199 if sched.npidle.Load() == gomaxprocs-1 && sched.lastpoll.Load() != 0 {
3200 unlock(&sched.lock)
3201 startm(pp, false, false)
3202 return
3203 }
3204
3205
3206
3207 when := pp.timers.wakeTime()
3208 pidleput(pp, 0)
3209 unlock(&sched.lock)
3210
3211 if when != 0 {
3212 wakeNetPoller(when)
3213 }
3214 }
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229 func wakep() {
3230
3231
3232 if sched.nmspinning.Load() != 0 || !sched.nmspinning.CompareAndSwap(0, 1) {
3233 return
3234 }
3235
3236
3237
3238
3239
3240
3241 mp := acquirem()
3242
3243 var pp *p
3244 lock(&sched.lock)
3245 pp, _ = pidlegetSpinning(0)
3246 if pp == nil {
3247 if sched.nmspinning.Add(-1) < 0 {
3248 throw("wakep: negative nmspinning")
3249 }
3250 unlock(&sched.lock)
3251 releasem(mp)
3252 return
3253 }
3254
3255
3256
3257
3258 unlock(&sched.lock)
3259
3260 startm(pp, true, false)
3261
3262 releasem(mp)
3263 }
3264
3265
3266
3267 func stoplockedm() {
3268 gp := getg()
3269
3270 if gp.m.lockedg == 0 || gp.m.lockedg.ptr().lockedm.ptr() != gp.m {
3271 throw("stoplockedm: inconsistent locking")
3272 }
3273 if gp.m.p != 0 {
3274
3275 pp := releasep()
3276 handoffp(pp)
3277 }
3278 incidlelocked(1)
3279
3280 mPark()
3281 status := readgstatus(gp.m.lockedg.ptr())
3282 if status&^_Gscan != _Grunnable {
3283 print("runtime:stoplockedm: lockedg (atomicstatus=", status, ") is not Grunnable or Gscanrunnable\n")
3284 dumpgstatus(gp.m.lockedg.ptr())
3285 throw("stoplockedm: not runnable")
3286 }
3287 acquirep(gp.m.nextp.ptr())
3288 gp.m.nextp = 0
3289 }
3290
3291
3292
3293
3294
3295 func startlockedm(gp *g) {
3296 mp := gp.lockedm.ptr()
3297 if mp == getg().m {
3298 throw("startlockedm: locked to me")
3299 }
3300 if mp.nextp != 0 {
3301 throw("startlockedm: m has p")
3302 }
3303
3304 incidlelocked(-1)
3305 pp := releasep()
3306 mp.nextp.set(pp)
3307 notewakeup(&mp.park)
3308 stopm()
3309 }
3310
3311
3312
3313 func gcstopm() {
3314 gp := getg()
3315
3316 if !sched.gcwaiting.Load() {
3317 throw("gcstopm: not waiting for gc")
3318 }
3319 if gp.m.spinning {
3320 gp.m.spinning = false
3321
3322
3323 if sched.nmspinning.Add(-1) < 0 {
3324 throw("gcstopm: negative nmspinning")
3325 }
3326 }
3327 pp := releasep()
3328 lock(&sched.lock)
3329 pp.status = _Pgcstop
3330 pp.gcStopTime = nanotime()
3331 sched.stopwait--
3332 if sched.stopwait == 0 {
3333 notewakeup(&sched.stopnote)
3334 }
3335 unlock(&sched.lock)
3336 stopm()
3337 }
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348 func execute(gp *g, inheritTime bool) {
3349 mp := getg().m
3350
3351 if goroutineProfile.active {
3352
3353
3354
3355 tryRecordGoroutineProfile(gp, nil, osyield)
3356 }
3357
3358
3359 mp.curg = gp
3360 gp.m = mp
3361 gp.syncSafePoint = false
3362 casgstatus(gp, _Grunnable, _Grunning)
3363 gp.waitsince = 0
3364 gp.preempt = false
3365 gp.stackguard0 = gp.stack.lo + stackGuard
3366 if !inheritTime {
3367 mp.p.ptr().schedtick++
3368 }
3369
3370 if sys.DITSupported && debug.dataindependenttiming != 1 {
3371 if gp.ditWanted && !mp.ditEnabled {
3372
3373
3374 sys.EnableDIT()
3375 mp.ditEnabled = true
3376 } else if !gp.ditWanted && mp.ditEnabled {
3377
3378
3379
3380
3381
3382 sys.DisableDIT()
3383 mp.ditEnabled = false
3384 }
3385 }
3386
3387
3388 hz := sched.profilehz
3389 if mp.profilehz != hz {
3390 setThreadCPUProfiler(hz)
3391 }
3392
3393 trace := traceAcquire()
3394 if trace.ok() {
3395 trace.GoStart()
3396 traceRelease(trace)
3397 }
3398
3399
3400
3401
3402
3403
3404
3405 if mp.p.ptr().runSafePointFn != 0 {
3406 runSafePointFn()
3407 }
3408
3409 gogo(&gp.sched)
3410 }
3411
3412
3413
3414
3415
3416 func findRunnable() (gp *g, inheritTime, tryWakeP bool) {
3417 mp := getg().m
3418
3419
3420
3421
3422
3423 top:
3424
3425
3426
3427 mp.clearAllpSnapshot()
3428
3429 pp := mp.p.ptr()
3430 if sched.gcwaiting.Load() {
3431 gcstopm()
3432 goto top
3433 }
3434 if pp.runSafePointFn != 0 {
3435 runSafePointFn()
3436 }
3437
3438
3439
3440
3441
3442 now, pollUntil, _ := pp.timers.check(0, nil)
3443
3444
3445 if traceEnabled() || traceShuttingDown() {
3446 gp := traceReader()
3447 if gp != nil {
3448 trace := traceAcquire()
3449 casgstatus(gp, _Gwaiting, _Grunnable)
3450 if trace.ok() {
3451 trace.GoUnpark(gp, 0)
3452 traceRelease(trace)
3453 }
3454 return gp, false, true
3455 }
3456 }
3457
3458
3459 if gcBlackenEnabled != 0 {
3460 gp, tnow := gcController.findRunnableGCWorker(pp, now)
3461 if gp != nil {
3462 return gp, false, true
3463 }
3464 now = tnow
3465 }
3466
3467
3468
3469
3470 if pp.schedtick%61 == 0 && !sched.runq.empty() {
3471 lock(&sched.lock)
3472 gp := globrunqget()
3473 unlock(&sched.lock)
3474 if gp != nil {
3475 return gp, false, false
3476 }
3477 }
3478
3479
3480 if fingStatus.Load()&(fingWait|fingWake) == fingWait|fingWake {
3481 if gp := wakefing(); gp != nil {
3482 ready(gp, 0, true)
3483 }
3484 }
3485
3486
3487 if gcCleanups.needsWake() {
3488 gcCleanups.wake()
3489 }
3490
3491 if *cgo_yield != nil {
3492 asmcgocall(*cgo_yield, nil)
3493 }
3494
3495
3496 if gp, inheritTime := runqget(pp); gp != nil {
3497 return gp, inheritTime, false
3498 }
3499
3500
3501 if !sched.runq.empty() {
3502 lock(&sched.lock)
3503 gp, q := globrunqgetbatch(int32(len(pp.runq)) / 2)
3504 unlock(&sched.lock)
3505 if gp != nil {
3506 if runqputbatch(pp, &q); !q.empty() {
3507 throw("Couldn't put Gs into empty local runq")
3508 }
3509 return gp, false, false
3510 }
3511 }
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522 if netpollinited() && netpollAnyWaiters() && sched.lastpoll.Load() != 0 && sched.pollingNet.Swap(1) == 0 {
3523 list, delta := netpoll(0)
3524 sched.pollingNet.Store(0)
3525 if !list.empty() {
3526 gp := list.pop()
3527 injectglist(&list)
3528 netpollAdjustWaiters(delta)
3529 trace := traceAcquire()
3530 casgstatus(gp, _Gwaiting, _Grunnable)
3531 if trace.ok() {
3532 trace.GoUnpark(gp, 0)
3533 traceRelease(trace)
3534 }
3535 return gp, false, false
3536 }
3537 }
3538
3539
3540
3541
3542
3543
3544 if mp.spinning || 2*sched.nmspinning.Load() < gomaxprocs-sched.npidle.Load() {
3545 if !mp.spinning {
3546 mp.becomeSpinning()
3547 }
3548
3549 gp, inheritTime, tnow, w, newWork := stealWork(now)
3550 if gp != nil {
3551
3552 return gp, inheritTime, false
3553 }
3554 if newWork {
3555
3556
3557 goto top
3558 }
3559
3560 now = tnow
3561 if w != 0 && (pollUntil == 0 || w < pollUntil) {
3562
3563 pollUntil = w
3564 }
3565 }
3566
3567
3568
3569
3570
3571 if gcBlackenEnabled != 0 && gcShouldScheduleWorker(pp) && gcController.addIdleMarkWorker() {
3572 node := (*gcBgMarkWorkerNode)(gcBgMarkWorkerPool.pop())
3573 if node != nil {
3574 pp.gcMarkWorkerMode = gcMarkWorkerIdleMode
3575 gp := node.gp.ptr()
3576
3577 trace := traceAcquire()
3578 casgstatus(gp, _Gwaiting, _Grunnable)
3579 if trace.ok() {
3580 trace.GoUnpark(gp, 0)
3581 traceRelease(trace)
3582 }
3583 return gp, false, false
3584 }
3585 gcController.removeIdleMarkWorker()
3586 }
3587
3588
3589
3590
3591
3592 gp, otherReady := beforeIdle(now, pollUntil)
3593 if gp != nil {
3594 trace := traceAcquire()
3595 casgstatus(gp, _Gwaiting, _Grunnable)
3596 if trace.ok() {
3597 trace.GoUnpark(gp, 0)
3598 traceRelease(trace)
3599 }
3600 return gp, false, false
3601 }
3602 if otherReady {
3603 goto top
3604 }
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614 allpSnapshot := mp.snapshotAllp()
3615
3616
3617 idlepMaskSnapshot := idlepMask
3618 timerpMaskSnapshot := timerpMask
3619
3620
3621 lock(&sched.lock)
3622 if sched.gcwaiting.Load() || pp.runSafePointFn != 0 {
3623 unlock(&sched.lock)
3624 goto top
3625 }
3626 if !sched.runq.empty() {
3627 gp, q := globrunqgetbatch(int32(len(pp.runq)) / 2)
3628 unlock(&sched.lock)
3629 if gp == nil {
3630 throw("global runq empty with non-zero runqsize")
3631 }
3632 if runqputbatch(pp, &q); !q.empty() {
3633 throw("Couldn't put Gs into empty local runq")
3634 }
3635 return gp, false, false
3636 }
3637 if !mp.spinning && sched.needspinning.Load() == 1 {
3638
3639 mp.becomeSpinning()
3640 unlock(&sched.lock)
3641 goto top
3642 }
3643 if releasep() != pp {
3644 throw("findRunnable: wrong p")
3645 }
3646 now = pidleput(pp, now)
3647 unlock(&sched.lock)
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685 wasSpinning := mp.spinning
3686 if mp.spinning {
3687 mp.spinning = false
3688 if sched.nmspinning.Add(-1) < 0 {
3689 throw("findRunnable: negative nmspinning")
3690 }
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703 lock(&sched.lock)
3704 if !sched.runq.empty() {
3705 pp, _ := pidlegetSpinning(0)
3706 if pp != nil {
3707 gp, q := globrunqgetbatch(int32(len(pp.runq)) / 2)
3708 unlock(&sched.lock)
3709 if gp == nil {
3710 throw("global runq empty with non-zero runqsize")
3711 }
3712 if runqputbatch(pp, &q); !q.empty() {
3713 throw("Couldn't put Gs into empty local runq")
3714 }
3715 acquirep(pp)
3716 mp.becomeSpinning()
3717 return gp, false, false
3718 }
3719 }
3720 unlock(&sched.lock)
3721
3722 pp := checkRunqsNoP(allpSnapshot, idlepMaskSnapshot)
3723 if pp != nil {
3724 acquirep(pp)
3725 mp.becomeSpinning()
3726 goto top
3727 }
3728
3729
3730 pp, gp := checkIdleGCNoP()
3731 if pp != nil {
3732 acquirep(pp)
3733 mp.becomeSpinning()
3734
3735
3736 pp.gcMarkWorkerMode = gcMarkWorkerIdleMode
3737 trace := traceAcquire()
3738 casgstatus(gp, _Gwaiting, _Grunnable)
3739 if trace.ok() {
3740 trace.GoUnpark(gp, 0)
3741 traceRelease(trace)
3742 }
3743 return gp, false, false
3744 }
3745
3746
3747
3748
3749
3750
3751
3752 pollUntil = checkTimersNoP(allpSnapshot, timerpMaskSnapshot, pollUntil)
3753 }
3754
3755
3756
3757
3758
3759 if netpollinited() && (netpollAnyWaiters() || pollUntil != 0) && sched.lastpoll.Swap(0) != 0 {
3760 sched.pollUntil.Store(pollUntil)
3761 if mp.p != 0 {
3762 throw("findRunnable: netpoll with p")
3763 }
3764 if mp.spinning {
3765 throw("findRunnable: netpoll with spinning")
3766 }
3767 delay := int64(-1)
3768 if pollUntil != 0 {
3769 if now == 0 {
3770 now = nanotime()
3771 }
3772 delay = pollUntil - now
3773 if delay < 0 {
3774 delay = 0
3775 }
3776 }
3777 if faketime != 0 {
3778
3779 delay = 0
3780 }
3781 list, delta := netpoll(delay)
3782
3783 now = nanotime()
3784 sched.pollUntil.Store(0)
3785 sched.lastpoll.Store(now)
3786 if faketime != 0 && list.empty() {
3787
3788
3789 stopm()
3790 goto top
3791 }
3792 lock(&sched.lock)
3793 pp, _ := pidleget(now)
3794 unlock(&sched.lock)
3795 if pp == nil {
3796 injectglist(&list)
3797 netpollAdjustWaiters(delta)
3798 } else {
3799 acquirep(pp)
3800 if !list.empty() {
3801 gp := list.pop()
3802 injectglist(&list)
3803 netpollAdjustWaiters(delta)
3804 trace := traceAcquire()
3805 casgstatus(gp, _Gwaiting, _Grunnable)
3806 if trace.ok() {
3807 trace.GoUnpark(gp, 0)
3808 traceRelease(trace)
3809 }
3810 return gp, false, false
3811 }
3812 if wasSpinning {
3813 mp.becomeSpinning()
3814 }
3815 goto top
3816 }
3817 } else if pollUntil != 0 && netpollinited() {
3818 pollerPollUntil := sched.pollUntil.Load()
3819 if pollerPollUntil == 0 || pollerPollUntil > pollUntil {
3820 netpollBreak()
3821 }
3822 }
3823 stopm()
3824 goto top
3825 }
3826
3827
3828
3829
3830
3831 func pollWork() bool {
3832 if !sched.runq.empty() {
3833 return true
3834 }
3835 p := getg().m.p.ptr()
3836 if !runqempty(p) {
3837 return true
3838 }
3839 if netpollinited() && netpollAnyWaiters() && sched.lastpoll.Load() != 0 {
3840 if list, delta := netpoll(0); !list.empty() {
3841 injectglist(&list)
3842 netpollAdjustWaiters(delta)
3843 return true
3844 }
3845 }
3846 return false
3847 }
3848
3849
3850
3851
3852
3853
3854
3855 func stealWork(now int64) (gp *g, inheritTime bool, rnow, pollUntil int64, newWork bool) {
3856 pp := getg().m.p.ptr()
3857
3858 ranTimer := false
3859
3860 const stealTries = 4
3861 for i := 0; i < stealTries; i++ {
3862 stealTimersOrRunNextG := i == stealTries-1
3863
3864 for enum := stealOrder.start(cheaprand()); !enum.done(); enum.next() {
3865 p2 := allp[enum.position()]
3866 if pp == p2 {
3867 continue
3868 }
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883 if stealTimersOrRunNextG && timerpMask.read(enum.position()) {
3884 tnow, w, ran := p2.timers.check(now, nil)
3885 now = tnow
3886 if w != 0 && (pollUntil == 0 || w < pollUntil) {
3887 pollUntil = w
3888 }
3889 if ran {
3890
3891
3892
3893
3894
3895
3896
3897
3898 if gp, inheritTime := runqget(pp); gp != nil {
3899 return gp, inheritTime, now, pollUntil, ranTimer
3900 }
3901 ranTimer = true
3902 }
3903 }
3904
3905
3906 if !idlepMask.read(enum.position()) {
3907 if gp := runqsteal(pp, p2, stealTimersOrRunNextG); gp != nil {
3908 return gp, false, now, pollUntil, ranTimer
3909 }
3910 }
3911
3912 if sched.gcwaiting.Load() {
3913
3914
3915 return nil, false, now, pollUntil, true
3916 }
3917 }
3918 }
3919
3920
3921
3922
3923 return nil, false, now, pollUntil, ranTimer
3924 }
3925
3926
3927
3928
3929
3930
3931 func checkRunqsNoP(allpSnapshot []*p, idlepMaskSnapshot pMask) *p {
3932 for id, p2 := range allpSnapshot {
3933 if !idlepMaskSnapshot.read(uint32(id)) && !runqempty(p2) {
3934 lock(&sched.lock)
3935 pp, _ := pidlegetSpinning(0)
3936 if pp == nil {
3937
3938 unlock(&sched.lock)
3939 return nil
3940 }
3941 unlock(&sched.lock)
3942 return pp
3943 }
3944 }
3945
3946
3947 return nil
3948 }
3949
3950
3951
3952
3953 func checkTimersNoP(allpSnapshot []*p, timerpMaskSnapshot pMask, pollUntil int64) int64 {
3954 for id, p2 := range allpSnapshot {
3955 if timerpMaskSnapshot.read(uint32(id)) {
3956 w := p2.timers.wakeTime()
3957 if w != 0 && (pollUntil == 0 || w < pollUntil) {
3958 pollUntil = w
3959 }
3960 }
3961 }
3962
3963 return pollUntil
3964 }
3965
3966
3967
3968
3969
3970 func checkIdleGCNoP() (*p, *g) {
3971
3972
3973
3974
3975
3976
3977 if atomic.Load(&gcBlackenEnabled) == 0 || !gcController.needIdleMarkWorker() {
3978 return nil, nil
3979 }
3980 if !gcShouldScheduleWorker(nil) {
3981 return nil, nil
3982 }
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001 lock(&sched.lock)
4002 pp, now := pidlegetSpinning(0)
4003 if pp == nil {
4004 unlock(&sched.lock)
4005 return nil, nil
4006 }
4007
4008
4009 if gcBlackenEnabled == 0 || !gcController.addIdleMarkWorker() {
4010 pidleput(pp, now)
4011 unlock(&sched.lock)
4012 return nil, nil
4013 }
4014
4015 node := (*gcBgMarkWorkerNode)(gcBgMarkWorkerPool.pop())
4016 if node == nil {
4017 pidleput(pp, now)
4018 unlock(&sched.lock)
4019 gcController.removeIdleMarkWorker()
4020 return nil, nil
4021 }
4022
4023 unlock(&sched.lock)
4024
4025 return pp, node.gp.ptr()
4026 }
4027
4028
4029
4030
4031 func wakeNetPoller(when int64) {
4032 if sched.lastpoll.Load() == 0 {
4033
4034
4035
4036
4037 pollerPollUntil := sched.pollUntil.Load()
4038 if pollerPollUntil == 0 || pollerPollUntil > when {
4039 netpollBreak()
4040 }
4041 } else {
4042
4043
4044 if GOOS != "plan9" {
4045 wakep()
4046 }
4047 }
4048 }
4049
4050 func resetspinning() {
4051 gp := getg()
4052 if !gp.m.spinning {
4053 throw("resetspinning: not a spinning m")
4054 }
4055 gp.m.spinning = false
4056 nmspinning := sched.nmspinning.Add(-1)
4057 if nmspinning < 0 {
4058 throw("findRunnable: negative nmspinning")
4059 }
4060
4061
4062
4063 wakep()
4064 }
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074 func injectglist(glist *gList) {
4075 if glist.empty() {
4076 return
4077 }
4078
4079
4080
4081 var tail *g
4082 trace := traceAcquire()
4083 for gp := glist.head.ptr(); gp != nil; gp = gp.schedlink.ptr() {
4084 tail = gp
4085 casgstatus(gp, _Gwaiting, _Grunnable)
4086 if trace.ok() {
4087 trace.GoUnpark(gp, 0)
4088 }
4089 }
4090 if trace.ok() {
4091 traceRelease(trace)
4092 }
4093
4094
4095 q := gQueue{glist.head, tail.guintptr(), glist.size}
4096 *glist = gList{}
4097
4098 startIdle := func(n int32) {
4099 for ; n > 0; n-- {
4100 mp := acquirem()
4101 lock(&sched.lock)
4102
4103 pp, _ := pidlegetSpinning(0)
4104 if pp == nil {
4105 unlock(&sched.lock)
4106 releasem(mp)
4107 break
4108 }
4109
4110 startm(pp, false, true)
4111 unlock(&sched.lock)
4112 releasem(mp)
4113 }
4114 }
4115
4116 pp := getg().m.p.ptr()
4117 if pp == nil {
4118 n := q.size
4119 lock(&sched.lock)
4120 globrunqputbatch(&q)
4121 unlock(&sched.lock)
4122 startIdle(n)
4123 return
4124 }
4125
4126 var globq gQueue
4127 npidle := sched.npidle.Load()
4128 for ; npidle > 0 && !q.empty(); npidle-- {
4129 g := q.pop()
4130 globq.pushBack(g)
4131 }
4132 if !globq.empty() {
4133 n := globq.size
4134 lock(&sched.lock)
4135 globrunqputbatch(&globq)
4136 unlock(&sched.lock)
4137 startIdle(n)
4138 }
4139
4140 if runqputbatch(pp, &q); !q.empty() {
4141 lock(&sched.lock)
4142 globrunqputbatch(&q)
4143 unlock(&sched.lock)
4144 }
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159 wakep()
4160 }
4161
4162
4163
4164 func schedule() {
4165 mp := getg().m
4166
4167 if mp.locks != 0 {
4168 throw("schedule: holding locks")
4169 }
4170
4171 if mp.lockedg != 0 {
4172 stoplockedm()
4173 execute(mp.lockedg.ptr(), false)
4174 }
4175
4176
4177
4178 if mp.incgo {
4179 throw("schedule: in cgo")
4180 }
4181
4182 top:
4183 pp := mp.p.ptr()
4184 pp.preempt = false
4185
4186
4187
4188
4189 if mp.spinning && (pp.runnext != 0 || pp.runqhead != pp.runqtail) {
4190 throw("schedule: spinning with local work")
4191 }
4192
4193 gp, inheritTime, tryWakeP := findRunnable()
4194
4195
4196 pp = mp.p.ptr()
4197
4198
4199
4200
4201 mp.clearAllpSnapshot()
4202
4203
4204
4205
4206
4207
4208
4209
4210 gcController.releaseNextGCMarkWorker(pp)
4211
4212 if debug.dontfreezetheworld > 0 && freezing.Load() {
4213
4214
4215
4216
4217
4218
4219
4220 lock(&deadlock)
4221 lock(&deadlock)
4222 }
4223
4224
4225
4226
4227 if mp.spinning {
4228 resetspinning()
4229 }
4230
4231 if sched.disable.user && !schedEnabled(gp) {
4232
4233
4234
4235 lock(&sched.lock)
4236 if schedEnabled(gp) {
4237
4238
4239 unlock(&sched.lock)
4240 } else {
4241 sched.disable.runnable.pushBack(gp)
4242 unlock(&sched.lock)
4243 goto top
4244 }
4245 }
4246
4247
4248
4249 if tryWakeP {
4250 wakep()
4251 }
4252 if gp.lockedm != 0 {
4253
4254
4255 startlockedm(gp)
4256 goto top
4257 }
4258
4259 execute(gp, inheritTime)
4260 }
4261
4262
4263
4264
4265
4266
4267
4268
4269 func dropg() {
4270 gp := getg()
4271
4272 setMNoWB(&gp.m.curg.m, nil)
4273 setGNoWB(&gp.m.curg, nil)
4274 }
4275
4276 func parkunlock_c(gp *g, lock unsafe.Pointer) bool {
4277 unlock((*mutex)(lock))
4278 return true
4279 }
4280
4281
4282 func park_m(gp *g) {
4283 mp := getg().m
4284
4285 trace := traceAcquire()
4286
4287
4288
4289
4290
4291 bubble := gp.bubble
4292 if bubble != nil {
4293 bubble.incActive()
4294 }
4295
4296 if trace.ok() {
4297
4298
4299
4300 trace.GoPark(mp.waitTraceBlockReason, mp.waitTraceSkip)
4301 }
4302
4303
4304 casgstatus(gp, _Grunning, _Gwaiting)
4305 if trace.ok() {
4306 traceRelease(trace)
4307 }
4308
4309 dropg()
4310
4311 if fn := mp.waitunlockf; fn != nil {
4312 ok := fn(gp, mp.waitlock)
4313 mp.waitunlockf = nil
4314 mp.waitlock = nil
4315 if !ok {
4316 trace := traceAcquire()
4317 casgstatus(gp, _Gwaiting, _Grunnable)
4318 if bubble != nil {
4319 bubble.decActive()
4320 }
4321 if trace.ok() {
4322 trace.GoUnpark(gp, 2)
4323 traceRelease(trace)
4324 }
4325 execute(gp, true)
4326 }
4327 }
4328
4329 if bubble != nil {
4330 bubble.decActive()
4331 }
4332
4333 schedule()
4334 }
4335
4336 func goschedImpl(gp *g, preempted bool) {
4337 pp := gp.m.p.ptr()
4338 trace := traceAcquire()
4339 status := readgstatus(gp)
4340 if status&^_Gscan != _Grunning {
4341 dumpgstatus(gp)
4342 throw("bad g status")
4343 }
4344 if trace.ok() {
4345
4346
4347
4348 if preempted {
4349 trace.GoPreempt()
4350 } else {
4351 trace.GoSched()
4352 }
4353 }
4354 casgstatus(gp, _Grunning, _Grunnable)
4355 if trace.ok() {
4356 traceRelease(trace)
4357 }
4358
4359 dropg()
4360 if preempted && sched.gcwaiting.Load() {
4361
4362
4363 runqput(pp, gp, true)
4364 } else {
4365 lock(&sched.lock)
4366 globrunqput(gp)
4367 unlock(&sched.lock)
4368 }
4369
4370 if mainStarted {
4371 wakep()
4372 }
4373
4374 schedule()
4375 }
4376
4377
4378 func gosched_m(gp *g) {
4379 goschedImpl(gp, false)
4380 }
4381
4382
4383 func goschedguarded_m(gp *g) {
4384 if !canPreemptM(gp.m) {
4385 gogo(&gp.sched)
4386 }
4387 goschedImpl(gp, false)
4388 }
4389
4390 func gopreempt_m(gp *g) {
4391 goschedImpl(gp, true)
4392 }
4393
4394
4395
4396
4397 func preemptPark(gp *g) {
4398 status := readgstatus(gp)
4399 if status&^_Gscan != _Grunning {
4400 dumpgstatus(gp)
4401 throw("bad g status")
4402 }
4403
4404 if gp.asyncSafePoint {
4405
4406
4407
4408 f := findfunc(gp.sched.pc)
4409 if !f.valid() {
4410 throw("preempt at unknown pc")
4411 }
4412 if f.flag&abi.FuncFlagSPWrite != 0 {
4413 println("runtime: unexpected SPWRITE function", funcname(f), "in async preempt")
4414 throw("preempt SPWRITE")
4415 }
4416 }
4417
4418
4419
4420
4421
4422
4423
4424 casGToPreemptScan(gp, _Grunning, _Gscan|_Gpreempted)
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446 trace := traceAcquire()
4447 if trace.ok() {
4448 trace.GoPark(traceBlockPreempted, 0)
4449 }
4450
4451
4452
4453
4454 dropg()
4455
4456
4457 casfrom_Gscanstatus(gp, _Gscan|_Gpreempted, _Gpreempted)
4458 if trace.ok() {
4459 traceRelease(trace)
4460 }
4461
4462
4463 schedule()
4464 }
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480 func goyield() {
4481 checkTimeouts()
4482 mcall(goyield_m)
4483 }
4484
4485 func goyield_m(gp *g) {
4486 trace := traceAcquire()
4487 pp := gp.m.p.ptr()
4488 if trace.ok() {
4489
4490
4491
4492 trace.GoPreempt()
4493 }
4494 casgstatus(gp, _Grunning, _Grunnable)
4495 if trace.ok() {
4496 traceRelease(trace)
4497 }
4498 dropg()
4499 runqput(pp, gp, false)
4500 schedule()
4501 }
4502
4503
4504 func goexit1() {
4505 if raceenabled {
4506 if gp := getg(); gp.bubble != nil {
4507 racereleasemergeg(gp, gp.bubble.raceaddr())
4508 }
4509 racegoend()
4510 }
4511 trace := traceAcquire()
4512 if trace.ok() {
4513 trace.GoEnd()
4514 traceRelease(trace)
4515 }
4516 mcall(goexit0)
4517 }
4518
4519
4520 func goexit0(gp *g) {
4521 if goexperiment.RuntimeSecret && gp.secret > 0 {
4522
4523
4524 memclrNoHeapPointers(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo)
4525
4526
4527 }
4528 gdestroy(gp)
4529 schedule()
4530 }
4531
4532 func gdestroy(gp *g) {
4533 mp := getg().m
4534 pp := mp.p.ptr()
4535
4536 casgstatus(gp, _Grunning, _Gdead)
4537 gcController.addScannableStack(pp, -int64(gp.stack.hi-gp.stack.lo))
4538 if isSystemGoroutine(gp, false) {
4539 sched.ngsys.Add(-1)
4540 }
4541 gp.m = nil
4542 locked := gp.lockedm != 0
4543 gp.lockedm = 0
4544 mp.lockedg = 0
4545 gp.preemptStop = false
4546 gp.paniconfault = false
4547 gp._defer = nil
4548 gp._panic = nil
4549 gp.writebuf = nil
4550 gp.waitreason = waitReasonZero
4551 gp.param = nil
4552 gp.labels = nil
4553 gp.timer = nil
4554 gp.bubble = nil
4555 gp.fipsOnlyBypass = false
4556 gp.secret = 0
4557
4558 if gcBlackenEnabled != 0 && gp.gcAssistBytes > 0 {
4559
4560
4561
4562 assistWorkPerByte := gcController.assistWorkPerByte.Load()
4563 scanCredit := int64(assistWorkPerByte * float64(gp.gcAssistBytes))
4564 gcController.bgScanCredit.Add(scanCredit)
4565 gp.gcAssistBytes = 0
4566 }
4567
4568 dropg()
4569
4570 if GOARCH == "wasm" {
4571 gfput(pp, gp)
4572 return
4573 }
4574
4575 if locked && mp.lockedInt != 0 {
4576 print("runtime: mp.lockedInt = ", mp.lockedInt, "\n")
4577 if mp.isextra {
4578 throw("runtime.Goexit called in a thread that was not created by the Go runtime")
4579 }
4580 throw("exited a goroutine internally locked to the OS thread")
4581 }
4582 gfput(pp, gp)
4583 if locked {
4584
4585
4586
4587
4588
4589
4590 if GOOS != "plan9" {
4591 gogo(&mp.g0.sched)
4592 } else {
4593
4594
4595 mp.lockedExt = 0
4596 }
4597 }
4598 }
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608 func save(pc, sp, bp uintptr) {
4609 gp := getg()
4610
4611 if gp == gp.m.g0 || gp == gp.m.gsignal {
4612
4613
4614
4615
4616
4617 throw("save on system g not allowed")
4618 }
4619
4620 gp.sched.pc = pc
4621 gp.sched.sp = sp
4622 gp.sched.lr = 0
4623 gp.sched.bp = bp
4624
4625
4626
4627 if gp.sched.ctxt != nil {
4628 badctxt()
4629 }
4630 }
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656 func reentersyscall(pc, sp, bp uintptr) {
4657 gp := getg()
4658
4659
4660
4661 gp.m.locks++
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683 if goexperiment.RuntimeSecret {
4684 eraseSecretsSignalStk()
4685 }
4686
4687
4688
4689
4690
4691 gp.stackguard0 = stackPreempt
4692 gp.throwsplit = true
4693
4694
4695 gp.m.syscalltick = gp.m.p.ptr().syscalltick
4696
4697 pp := gp.m.p.ptr()
4698 if pp.runSafePointFn != 0 {
4699
4700 systemstack(runSafePointFn)
4701 }
4702 gp.m.oldp.set(pp)
4703
4704
4705 save(pc, sp, bp)
4706 gp.syscallsp = sp
4707 gp.syscallpc = pc
4708 gp.syscallbp = bp
4709
4710
4711 if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp {
4712 systemstack(func() {
4713 print("entersyscall inconsistent sp ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
4714 throw("entersyscall")
4715 })
4716 }
4717 if gp.syscallbp != 0 && gp.syscallbp < gp.stack.lo || gp.stack.hi < gp.syscallbp {
4718 systemstack(func() {
4719 print("entersyscall inconsistent bp ", hex(gp.syscallbp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
4720 throw("entersyscall")
4721 })
4722 }
4723 trace := traceAcquire()
4724 if trace.ok() {
4725
4726
4727
4728
4729 systemstack(func() {
4730 trace.GoSysCall()
4731 })
4732
4733 save(pc, sp, bp)
4734 }
4735 if sched.gcwaiting.Load() {
4736
4737
4738
4739 systemstack(func() {
4740 entersyscallHandleGCWait(trace)
4741 })
4742
4743 save(pc, sp, bp)
4744 }
4745
4746
4747
4748
4749
4750 if gp.bubble != nil || !gp.atomicstatus.CompareAndSwap(_Grunning, _Gsyscall) {
4751 casgstatus(gp, _Grunning, _Gsyscall)
4752 }
4753 if staticLockRanking {
4754
4755 save(pc, sp, bp)
4756 }
4757 if trace.ok() {
4758
4759
4760
4761 traceRelease(trace)
4762 }
4763 if sched.sysmonwait.Load() {
4764 systemstack(entersyscallWakeSysmon)
4765
4766 save(pc, sp, bp)
4767 }
4768 gp.m.locks--
4769 }
4770
4771
4772
4773
4774 const debugExtendGrunningNoP = false
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790 func entersyscall() {
4791
4792
4793
4794
4795 fp := getcallerfp()
4796 reentersyscall(sys.GetCallerPC(), sys.GetCallerSP(), fp)
4797 }
4798
4799 func entersyscallWakeSysmon() {
4800 lock(&sched.lock)
4801 if sched.sysmonwait.Load() {
4802 sched.sysmonwait.Store(false)
4803 notewakeup(&sched.sysmonnote)
4804 }
4805 unlock(&sched.lock)
4806 }
4807
4808 func entersyscallHandleGCWait(trace traceLocker) {
4809 gp := getg()
4810
4811 lock(&sched.lock)
4812 if sched.stopwait > 0 {
4813
4814 pp := gp.m.p.ptr()
4815 pp.m = 0
4816 gp.m.p = 0
4817 atomic.Store(&pp.status, _Pgcstop)
4818
4819 if trace.ok() {
4820 trace.ProcStop(pp)
4821 }
4822 addGSyscallNoP(gp.m)
4823 pp.gcStopTime = nanotime()
4824 pp.syscalltick++
4825 if sched.stopwait--; sched.stopwait == 0 {
4826 notewakeup(&sched.stopnote)
4827 }
4828 }
4829 unlock(&sched.lock)
4830 }
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844 func entersyscallblock() {
4845 gp := getg()
4846
4847 gp.m.locks++
4848 gp.throwsplit = true
4849 gp.stackguard0 = stackPreempt
4850 gp.m.syscalltick = gp.m.p.ptr().syscalltick
4851 gp.m.p.ptr().syscalltick++
4852
4853 addGSyscallNoP(gp.m)
4854
4855
4856 pc := sys.GetCallerPC()
4857 sp := sys.GetCallerSP()
4858 bp := getcallerfp()
4859 save(pc, sp, bp)
4860 gp.syscallsp = gp.sched.sp
4861 gp.syscallpc = gp.sched.pc
4862 gp.syscallbp = gp.sched.bp
4863 if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp {
4864 sp1 := sp
4865 sp2 := gp.sched.sp
4866 sp3 := gp.syscallsp
4867 systemstack(func() {
4868 print("entersyscallblock inconsistent sp ", hex(sp1), " ", hex(sp2), " ", hex(sp3), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
4869 throw("entersyscallblock")
4870 })
4871 }
4872
4873
4874
4875
4876
4877
4878 trace := traceAcquire()
4879 systemstack(func() {
4880 if trace.ok() {
4881 trace.GoSysCall()
4882 }
4883 handoffp(releasep())
4884 })
4885
4886
4887
4888 if debugExtendGrunningNoP {
4889 usleep(10)
4890 }
4891 casgstatus(gp, _Grunning, _Gsyscall)
4892 if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp {
4893 systemstack(func() {
4894 print("entersyscallblock inconsistent sp ", hex(sp), " ", hex(gp.sched.sp), " ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
4895 throw("entersyscallblock")
4896 })
4897 }
4898 if gp.syscallbp != 0 && gp.syscallbp < gp.stack.lo || gp.stack.hi < gp.syscallbp {
4899 systemstack(func() {
4900 print("entersyscallblock inconsistent bp ", hex(bp), " ", hex(gp.sched.bp), " ", hex(gp.syscallbp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
4901 throw("entersyscallblock")
4902 })
4903 }
4904 if trace.ok() {
4905 systemstack(func() {
4906 traceRelease(trace)
4907 })
4908 }
4909
4910
4911 save(sys.GetCallerPC(), sys.GetCallerSP(), getcallerfp())
4912
4913 gp.m.locks--
4914 }
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936 func exitsyscall() {
4937 gp := getg()
4938
4939 gp.m.locks++
4940 if sys.GetCallerSP() > gp.syscallsp {
4941 throw("exitsyscall: syscall frame is no longer valid")
4942 }
4943 gp.waitsince = 0
4944
4945 if sched.stopwait == freezeStopWait {
4946
4947
4948
4949 systemstack(func() {
4950 lock(&deadlock)
4951 lock(&deadlock)
4952 })
4953 }
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966 if gp.bubble != nil || !gp.atomicstatus.CompareAndSwap(_Gsyscall, _Grunning) {
4967 casgstatus(gp, _Gsyscall, _Grunning)
4968 }
4969
4970
4971
4972
4973 if debugExtendGrunningNoP {
4974 usleep(10)
4975 }
4976
4977
4978 oldp := gp.m.oldp.ptr()
4979 gp.m.oldp.set(nil)
4980
4981
4982 pp := gp.m.p.ptr()
4983 if pp != nil {
4984
4985 if trace := traceAcquire(); trace.ok() {
4986 systemstack(func() {
4987
4988
4989
4990
4991
4992
4993
4994
4995 if pp.syscalltick == gp.m.syscalltick {
4996 trace.GoSysExit(false)
4997 } else {
4998
4999
5000
5001
5002 trace.ProcSteal(pp)
5003 trace.ProcStart()
5004 trace.GoSysExit(true)
5005 trace.GoStart()
5006 }
5007 traceRelease(trace)
5008 })
5009 }
5010 } else {
5011
5012 systemstack(func() {
5013
5014 if pp := exitsyscallTryGetP(oldp); pp != nil {
5015
5016 acquirepNoTrace(pp)
5017
5018
5019 if trace := traceAcquire(); trace.ok() {
5020 trace.ProcStart()
5021 trace.GoSysExit(true)
5022 trace.GoStart()
5023 traceRelease(trace)
5024 }
5025 }
5026 })
5027 pp = gp.m.p.ptr()
5028 }
5029
5030
5031 if pp != nil {
5032 if goroutineProfile.active {
5033
5034
5035
5036 systemstack(func() {
5037 tryRecordGoroutineProfileWB(gp)
5038 })
5039 }
5040
5041
5042 pp.syscalltick++
5043
5044
5045
5046 gp.syscallsp = 0
5047 gp.m.locks--
5048 if gp.preempt {
5049
5050 gp.stackguard0 = stackPreempt
5051 } else {
5052
5053 gp.stackguard0 = gp.stack.lo + stackGuard
5054 }
5055 gp.throwsplit = false
5056
5057 if sched.disable.user && !schedEnabled(gp) {
5058
5059 Gosched()
5060 }
5061 return
5062 }
5063
5064 gp.m.locks--
5065
5066
5067 mcall(exitsyscallNoP)
5068
5069
5070
5071
5072
5073
5074
5075 gp.syscallsp = 0
5076 gp.m.p.ptr().syscalltick++
5077 gp.throwsplit = false
5078 }
5079
5080
5081
5082
5083
5084
5085
5086 func exitsyscallTryGetP(oldp *p) *p {
5087
5088 if oldp != nil {
5089 if thread, ok := setBlockOnExitSyscall(oldp); ok {
5090 thread.takeP()
5091 decGSyscallNoP(getg().m)
5092 thread.resume()
5093 return oldp
5094 }
5095 }
5096
5097
5098 if sched.pidle != 0 {
5099 lock(&sched.lock)
5100 pp, _ := pidleget(0)
5101 if pp != nil && sched.sysmonwait.Load() {
5102 sched.sysmonwait.Store(false)
5103 notewakeup(&sched.sysmonnote)
5104 }
5105 unlock(&sched.lock)
5106 if pp != nil {
5107 decGSyscallNoP(getg().m)
5108 return pp
5109 }
5110 }
5111 return nil
5112 }
5113
5114
5115
5116
5117
5118
5119
5120 func exitsyscallNoP(gp *g) {
5121 traceExitingSyscall()
5122 trace := traceAcquire()
5123 casgstatus(gp, _Grunning, _Grunnable)
5124 traceExitedSyscall()
5125 if trace.ok() {
5126
5127
5128
5129
5130 trace.GoSysExit(true)
5131 traceRelease(trace)
5132 }
5133 decGSyscallNoP(getg().m)
5134 dropg()
5135 lock(&sched.lock)
5136 var pp *p
5137 if schedEnabled(gp) {
5138 pp, _ = pidleget(0)
5139 }
5140 var locked bool
5141 if pp == nil {
5142 globrunqput(gp)
5143
5144
5145
5146
5147
5148
5149 locked = gp.lockedm != 0
5150 } else if sched.sysmonwait.Load() {
5151 sched.sysmonwait.Store(false)
5152 notewakeup(&sched.sysmonnote)
5153 }
5154 unlock(&sched.lock)
5155 if pp != nil {
5156 acquirep(pp)
5157 execute(gp, false)
5158 }
5159 if locked {
5160
5161
5162
5163
5164 stoplockedm()
5165 execute(gp, false)
5166 }
5167 stopm()
5168 schedule()
5169 }
5170
5171
5172
5173
5174
5175
5176
5177 func addGSyscallNoP(mp *m) {
5178
5179
5180
5181 if !mp.isExtraInC {
5182
5183
5184
5185
5186
5187 sched.nGsyscallNoP.Add(1)
5188 }
5189 }
5190
5191
5192
5193
5194
5195
5196
5197 func decGSyscallNoP(mp *m) {
5198
5199
5200
5201 if !mp.isExtraInC {
5202 sched.nGsyscallNoP.Add(-1)
5203 }
5204 }
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218 func syscall_runtime_BeforeFork() {
5219 gp := getg().m.curg
5220
5221
5222
5223
5224 gp.m.locks++
5225 sigsave(&gp.m.sigmask)
5226 sigblock(false)
5227
5228
5229
5230
5231
5232 gp.stackguard0 = stackFork
5233 }
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247 func syscall_runtime_AfterFork() {
5248 gp := getg().m.curg
5249
5250
5251 gp.stackguard0 = gp.stack.lo + stackGuard
5252
5253 msigrestore(gp.m.sigmask)
5254
5255 gp.m.locks--
5256 }
5257
5258
5259
5260 var inForkedChild bool
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281 func syscall_runtime_AfterForkInChild() {
5282
5283
5284
5285
5286 inForkedChild = true
5287
5288 clearSignalHandlers()
5289
5290
5291
5292 msigrestore(getg().m.sigmask)
5293
5294 inForkedChild = false
5295 }
5296
5297
5298
5299
5300 var pendingPreemptSignals atomic.Int32
5301
5302
5303
5304
5305 func syscall_runtime_BeforeExec() {
5306
5307 execLock.lock()
5308
5309
5310
5311 if GOOS == "darwin" || GOOS == "ios" {
5312 for pendingPreemptSignals.Load() > 0 {
5313 osyield()
5314 }
5315 }
5316 }
5317
5318
5319
5320
5321 func syscall_runtime_AfterExec() {
5322 execLock.unlock()
5323 }
5324
5325
5326 func malg(stacksize int32) *g {
5327 newg := new(g)
5328
5329
5330 wasmContAlloc(newg)
5331 if stacksize >= 0 {
5332 stacksize = round2(stackSystem + stacksize)
5333 systemstack(func() {
5334 newg.stack = stackalloc(uint32(stacksize))
5335 if valgrindenabled {
5336 valgrindRegisterStack(newg)
5337 }
5338 })
5339 newg.stackguard0 = newg.stack.lo + stackGuard
5340 newg.stackguard1 = ^uintptr(0)
5341
5342
5343 *(*uintptr)(unsafe.Pointer(newg.stack.lo)) = 0
5344 }
5345 return newg
5346 }
5347
5348
5349
5350
5351 func newproc(fn *funcval) {
5352 gp := getg()
5353 pc := sys.GetCallerPC()
5354 systemstack(func() {
5355 newg := newproc1(fn, gp, pc, false, waitReasonZero)
5356
5357 pp := getg().m.p.ptr()
5358 runqput(pp, newg, true)
5359
5360 if mainStarted {
5361 wakep()
5362 }
5363 })
5364 }
5365
5366
5367
5368
5369 func newproc1(fn *funcval, callergp *g, callerpc uintptr, parked bool, waitreason waitReason) *g {
5370 if fn == nil {
5371 fatal("go of nil func value")
5372 }
5373
5374 mp := acquirem()
5375 pp := mp.p.ptr()
5376 newg := gfget(pp)
5377 if newg == nil {
5378 newg = malg(stackMin)
5379 casgstatus(newg, _Gidle, _Gdead)
5380 allgadd(newg)
5381 }
5382 if newg.stack.hi == 0 {
5383 throw("newproc1: newg missing stack")
5384 }
5385
5386 if readgstatus(newg) != _Gdead {
5387 throw("newproc1: new g is not Gdead")
5388 }
5389
5390 totalSize := uintptr(4*goarch.PtrSize + sys.MinFrameSize)
5391 totalSize = alignUp(totalSize, sys.StackAlign)
5392 sp := newg.stack.hi - totalSize
5393 if usesLR {
5394
5395 *(*uintptr)(unsafe.Pointer(sp)) = 0
5396 prepGoExitFrame(sp)
5397 }
5398 if GOARCH == "arm64" {
5399
5400 *(*uintptr)(unsafe.Pointer(sp - goarch.PtrSize)) = 0
5401 }
5402
5403 memclrNoHeapPointers(unsafe.Pointer(&newg.sched), unsafe.Sizeof(newg.sched))
5404 newg.sched.sp = sp
5405 newg.stktopsp = sp
5406 newg.sched.pc = abi.FuncPCABI0(goexit) + sys.PCQuantum
5407 newg.sched.g = guintptr(unsafe.Pointer(newg))
5408 gostartcallfn(&newg.sched, fn)
5409 newg.parentGoid = callergp.goid
5410 newg.gopc = callerpc
5411 newg.ancestors = saveAncestors(callergp)
5412 newg.startpc = fn.fn
5413 newg.runningCleanups.Store(false)
5414 if isSystemGoroutine(newg, false) {
5415 sched.ngsys.Add(1)
5416 } else {
5417
5418 newg.bubble = callergp.bubble
5419 if mp.curg != nil {
5420 newg.labels = mp.curg.labels
5421 }
5422 if goroutineProfile.active {
5423
5424
5425
5426
5427
5428 newg.goroutineProfiled.Store(goroutineProfileSatisfied)
5429 }
5430 }
5431
5432 newg.trackingSeq = uint8(cheaprand())
5433 if newg.trackingSeq%gTrackingPeriod == 0 {
5434 newg.tracking = true
5435 }
5436 gcController.addScannableStack(pp, int64(newg.stack.hi-newg.stack.lo))
5437
5438
5439
5440 trace := traceAcquire()
5441 var status uint32 = _Grunnable
5442 if parked {
5443 status = _Gwaiting
5444 newg.waitreason = waitreason
5445 }
5446 if pp.goidcache == pp.goidcacheend {
5447
5448
5449
5450 pp.goidcache = sched.goidgen.Add(_GoidCacheBatch)
5451 pp.goidcache -= _GoidCacheBatch - 1
5452 pp.goidcacheend = pp.goidcache + _GoidCacheBatch
5453 }
5454 newg.goid = pp.goidcache
5455 casgstatus(newg, _Gdead, status)
5456 pp.goidcache++
5457 newg.trace.reset()
5458 if trace.ok() {
5459 trace.GoCreate(newg, newg.startpc, parked)
5460 traceRelease(trace)
5461 }
5462
5463
5464 newg.fipsOnlyBypass = callergp.fipsOnlyBypass
5465
5466
5467 newg.ditWanted = callergp.ditWanted
5468
5469 if goexperiment.RuntimeSecret && callergp.secret > 0 {
5470
5471
5472
5473
5474
5475
5476
5477
5478 newg.secret = 1
5479 }
5480
5481
5482 if raceenabled {
5483 newg.racectx = racegostart(callerpc)
5484 newg.raceignore = 0
5485 if newg.labels != nil {
5486
5487
5488 racereleasemergeg(newg, unsafe.Pointer(&labelSync))
5489 }
5490 }
5491 pp.goroutinesCreated++
5492 releasem(mp)
5493
5494 return newg
5495 }
5496
5497
5498
5499
5500 func saveAncestors(callergp *g) *[]ancestorInfo {
5501
5502 if debug.tracebackancestors <= 0 || callergp.goid == 0 {
5503 return nil
5504 }
5505 var callerAncestors []ancestorInfo
5506 if callergp.ancestors != nil {
5507 callerAncestors = *callergp.ancestors
5508 }
5509 n := int32(len(callerAncestors)) + 1
5510 if n > debug.tracebackancestors {
5511 n = debug.tracebackancestors
5512 }
5513 ancestors := make([]ancestorInfo, n)
5514 copy(ancestors[1:], callerAncestors)
5515
5516 var pcs [tracebackInnerFrames]uintptr
5517 npcs := gcallers(callergp, 0, pcs[:])
5518 ipcs := make([]uintptr, npcs)
5519 copy(ipcs, pcs[:])
5520 ancestors[0] = ancestorInfo{
5521 pcs: ipcs,
5522 goid: callergp.goid,
5523 gopc: callergp.gopc,
5524 }
5525
5526 ancestorsp := new([]ancestorInfo)
5527 *ancestorsp = ancestors
5528 return ancestorsp
5529 }
5530
5531
5532
5533 func gfput(pp *p, gp *g) {
5534 if readgstatus(gp) != _Gdead {
5535 throw("gfput: bad status (not Gdead)")
5536 }
5537
5538 stksize := gp.stack.hi - gp.stack.lo
5539
5540 if stksize != uintptr(startingStackSize) {
5541
5542 stackfree(gp.stack)
5543 gp.stack.lo = 0
5544 gp.stack.hi = 0
5545 gp.stackguard0 = 0
5546 if valgrindenabled {
5547 valgrindDeregisterStack(gp)
5548 }
5549 }
5550
5551 pp.gFree.push(gp)
5552 if pp.gFree.size >= 64 {
5553 var (
5554 stackQ gQueue
5555 noStackQ gQueue
5556 )
5557 for pp.gFree.size >= 32 {
5558 gp := pp.gFree.pop()
5559 if gp.stack.lo == 0 {
5560 noStackQ.push(gp)
5561 } else {
5562 stackQ.push(gp)
5563 }
5564 }
5565 lock(&sched.gFree.lock)
5566 sched.gFree.noStack.pushAll(noStackQ)
5567 sched.gFree.stack.pushAll(stackQ)
5568 unlock(&sched.gFree.lock)
5569 }
5570 }
5571
5572
5573
5574 func gfget(pp *p) *g {
5575 retry:
5576 if pp.gFree.empty() && (!sched.gFree.stack.empty() || !sched.gFree.noStack.empty()) {
5577 lock(&sched.gFree.lock)
5578
5579 for pp.gFree.size < 32 {
5580
5581 gp := sched.gFree.stack.pop()
5582 if gp == nil {
5583 gp = sched.gFree.noStack.pop()
5584 if gp == nil {
5585 break
5586 }
5587 }
5588 pp.gFree.push(gp)
5589 }
5590 unlock(&sched.gFree.lock)
5591 goto retry
5592 }
5593 gp := pp.gFree.pop()
5594 if gp == nil {
5595 return nil
5596 }
5597 if gp.stack.lo != 0 && gp.stack.hi-gp.stack.lo != uintptr(startingStackSize) {
5598
5599
5600
5601 systemstack(func() {
5602 stackfree(gp.stack)
5603 gp.stack.lo = 0
5604 gp.stack.hi = 0
5605 gp.stackguard0 = 0
5606 if valgrindenabled {
5607 valgrindDeregisterStack(gp)
5608 }
5609 })
5610 }
5611 if gp.stack.lo == 0 {
5612
5613 systemstack(func() {
5614 gp.stack = stackalloc(startingStackSize)
5615 if valgrindenabled {
5616 valgrindRegisterStack(gp)
5617 }
5618 })
5619 gp.stackguard0 = gp.stack.lo + stackGuard
5620 } else {
5621 if raceenabled {
5622 racemalloc(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo)
5623 }
5624 if msanenabled {
5625 msanmalloc(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo)
5626 }
5627 if asanenabled {
5628 asanunpoison(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo)
5629 }
5630 }
5631 return gp
5632 }
5633
5634
5635 func gfpurge(pp *p) {
5636 var (
5637 stackQ gQueue
5638 noStackQ gQueue
5639 )
5640 for !pp.gFree.empty() {
5641 gp := pp.gFree.pop()
5642 if gp.stack.lo == 0 {
5643 noStackQ.push(gp)
5644 } else {
5645 stackQ.push(gp)
5646 }
5647 }
5648 lock(&sched.gFree.lock)
5649 sched.gFree.noStack.pushAll(noStackQ)
5650 sched.gFree.stack.pushAll(stackQ)
5651 unlock(&sched.gFree.lock)
5652 }
5653
5654
5655 func Breakpoint() {
5656 breakpoint()
5657 }
5658
5659
5660
5661
5662
5663
5664 func dolockOSThread() {
5665 if GOARCH == "wasm" {
5666 return
5667 }
5668 gp := getg()
5669 gp.m.lockedg.set(gp)
5670 gp.lockedm.set(gp.m)
5671 }
5672
5673
5674
5675
5676
5677
5678
5679
5680
5681
5682
5683
5684
5685
5686
5687
5688
5689 func LockOSThread() {
5690 if atomic.Load(&newmHandoff.haveTemplateThread) == 0 && GOOS != "plan9" {
5691
5692
5693
5694 startTemplateThread()
5695 }
5696 gp := getg()
5697 gp.m.lockedExt++
5698 if gp.m.lockedExt == 0 {
5699 gp.m.lockedExt--
5700 panic("LockOSThread nesting overflow")
5701 }
5702 dolockOSThread()
5703 }
5704
5705
5706 func lockOSThread() {
5707 getg().m.lockedInt++
5708 dolockOSThread()
5709 }
5710
5711
5712
5713
5714
5715
5716 func dounlockOSThread() {
5717 if GOARCH == "wasm" {
5718 return
5719 }
5720 gp := getg()
5721 if gp.m.lockedInt != 0 || gp.m.lockedExt != 0 {
5722 return
5723 }
5724 gp.m.lockedg = 0
5725 gp.lockedm = 0
5726 }
5727
5728
5729
5730
5731
5732
5733
5734
5735
5736
5737
5738
5739
5740
5741
5742 func UnlockOSThread() {
5743 gp := getg()
5744 if gp.m.lockedExt == 0 {
5745 return
5746 }
5747 gp.m.lockedExt--
5748 dounlockOSThread()
5749 }
5750
5751
5752 func unlockOSThread() {
5753 gp := getg()
5754 if gp.m.lockedInt == 0 {
5755 systemstack(badunlockosthread)
5756 }
5757 gp.m.lockedInt--
5758 dounlockOSThread()
5759 }
5760
5761 func badunlockosthread() {
5762 throw("runtime: internal error: misuse of lockOSThread/unlockOSThread")
5763 }
5764
5765 func gcount(includeSys bool) int32 {
5766 n := int32(atomic.Loaduintptr(&allglen)) - sched.gFree.stack.size - sched.gFree.noStack.size
5767 if !includeSys {
5768 n -= sched.ngsys.Load()
5769 }
5770 for _, pp := range allp {
5771 n -= pp.gFree.size
5772 }
5773
5774
5775
5776 if n < 1 {
5777 n = 1
5778 }
5779 return n
5780 }
5781
5782
5783
5784
5785
5786 func goroutineleakcount() int {
5787 return work.goroutineLeak.count
5788 }
5789
5790 func mcount() int32 {
5791 return int32(sched.mnext - sched.nmfreed)
5792 }
5793
5794 var prof struct {
5795 signalLock atomic.Uint32
5796
5797
5798
5799 hz atomic.Int32
5800 }
5801
5802 func _System() { _System() }
5803 func _ExternalCode() { _ExternalCode() }
5804 func _LostExternalCode() { _LostExternalCode() }
5805 func _GC() { _GC() }
5806 func _LostSIGPROFDuringAtomic64() { _LostSIGPROFDuringAtomic64() }
5807 func _LostContendedRuntimeLock() { _LostContendedRuntimeLock() }
5808 func _VDSO() { _VDSO() }
5809
5810
5811
5812
5813
5814 func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
5815 if prof.hz.Load() == 0 {
5816 return
5817 }
5818
5819
5820
5821
5822 if mp != nil && mp.profilehz == 0 {
5823 return
5824 }
5825
5826
5827
5828
5829
5830
5831
5832 if GOARCH == "mips" || GOARCH == "mipsle" || GOARCH == "arm" {
5833 if f := findfunc(pc); f.valid() {
5834 if stringslite.HasPrefix(funcname(f), "internal/runtime/atomic") {
5835 cpuprof.lostAtomic++
5836 return
5837 }
5838 }
5839 if GOARCH == "arm" && goarm < 7 && GOOS == "linux" && pc&0xffff0000 == 0xffff0000 {
5840
5841
5842
5843 cpuprof.lostAtomic++
5844 return
5845 }
5846 }
5847
5848
5849
5850
5851
5852
5853
5854 getg().m.mallocing++
5855
5856 var u unwinder
5857 var stk [maxCPUProfStack]uintptr
5858 n := 0
5859 if mp.ncgo > 0 && mp.curg != nil && mp.curg.syscallpc != 0 && mp.curg.syscallsp != 0 {
5860 cgoOff := 0
5861
5862
5863
5864
5865
5866 if mp.cgoCallersUse.Load() == 0 && mp.cgoCallers != nil && mp.cgoCallers[0] != 0 {
5867 for cgoOff < len(mp.cgoCallers) && mp.cgoCallers[cgoOff] != 0 {
5868 cgoOff++
5869 }
5870 n += copy(stk[:], mp.cgoCallers[:cgoOff])
5871 mp.cgoCallers[0] = 0
5872 }
5873
5874
5875 u.initAt(mp.curg.syscallpc, mp.curg.syscallsp, 0, mp.curg, unwindSilentErrors)
5876 } else if usesLibcall() && mp.libcallg != 0 && mp.libcallpc != 0 && mp.libcallsp != 0 {
5877
5878
5879 u.initAt(mp.libcallpc, mp.libcallsp, 0, mp.libcallg.ptr(), unwindSilentErrors)
5880 } else if mp != nil && mp.vdsoSP != 0 {
5881
5882
5883 u.initAt(mp.vdsoPC, mp.vdsoSP, 0, gp, unwindSilentErrors|unwindJumpStack)
5884 } else {
5885 u.initAt(pc, sp, lr, gp, unwindSilentErrors|unwindTrap|unwindJumpStack)
5886 }
5887 n += tracebackPCs(&u, 0, stk[n:])
5888
5889 if n <= 0 {
5890
5891
5892 n = 2
5893 if inVDSOPage(pc) {
5894 pc = abi.FuncPCABIInternal(_VDSO) + sys.PCQuantum
5895 } else if pc > firstmoduledata.etext {
5896
5897 pc = abi.FuncPCABIInternal(_ExternalCode) + sys.PCQuantum
5898 }
5899 stk[0] = pc
5900 if mp.preemptoff != "" {
5901 stk[1] = abi.FuncPCABIInternal(_GC) + sys.PCQuantum
5902 } else {
5903 stk[1] = abi.FuncPCABIInternal(_System) + sys.PCQuantum
5904 }
5905 }
5906
5907 if prof.hz.Load() != 0 {
5908
5909
5910
5911 var tagPtr *unsafe.Pointer
5912 if gp != nil && gp.m != nil && gp.m.curg != nil {
5913 tagPtr = &gp.m.curg.labels
5914 }
5915 cpuprof.add(tagPtr, stk[:n])
5916
5917 gprof := gp
5918 var mp *m
5919 var pp *p
5920 if gp != nil && gp.m != nil {
5921 if gp.m.curg != nil {
5922 gprof = gp.m.curg
5923 }
5924 mp = gp.m
5925 pp = gp.m.p.ptr()
5926 }
5927 traceCPUSample(gprof, mp, pp, stk[:n])
5928 }
5929 getg().m.mallocing--
5930 }
5931
5932
5933
5934 func setcpuprofilerate(hz int32) {
5935
5936 if hz < 0 {
5937 hz = 0
5938 }
5939
5940
5941
5942 gp := getg()
5943 gp.m.locks++
5944
5945
5946
5947
5948 setThreadCPUProfiler(0)
5949
5950 for !prof.signalLock.CompareAndSwap(0, 1) {
5951 osyield()
5952 }
5953 if prof.hz.Load() != hz {
5954 setProcessCPUProfiler(hz)
5955 prof.hz.Store(hz)
5956 }
5957 prof.signalLock.Store(0)
5958
5959 lock(&sched.lock)
5960 sched.profilehz = hz
5961 unlock(&sched.lock)
5962
5963 if hz != 0 {
5964 setThreadCPUProfiler(hz)
5965 }
5966
5967 gp.m.locks--
5968 }
5969
5970
5971
5972 func (pp *p) init(id int32) {
5973 pp.id = id
5974 pp.gcw.id = id
5975 pp.status = _Pgcstop
5976 pp.waitingGCache = pp.waitingGBuf[:0]
5977 pp.deferpool = pp.deferpoolbuf[:0]
5978 pp.wbBuf.reset()
5979 if pp.mcache == nil {
5980 if id == 0 {
5981 if mcache0 == nil {
5982 throw("missing mcache?")
5983 }
5984
5985
5986 pp.mcache = mcache0
5987 } else {
5988 pp.mcache = allocmcache()
5989 }
5990 }
5991 if raceenabled && pp.raceprocctx == 0 {
5992 if id == 0 {
5993 pp.raceprocctx = raceprocctx0
5994 raceprocctx0 = 0
5995 } else {
5996 pp.raceprocctx = raceproccreate()
5997 }
5998 }
5999 lockInit(&pp.timers.mu, lockRankTimers)
6000
6001
6002
6003 timerpMask.set(id)
6004
6005
6006 idlepMask.clear(id)
6007 }
6008
6009
6010
6011
6012
6013 func (pp *p) destroy() {
6014 assertLockHeld(&sched.lock)
6015 assertWorldStopped()
6016
6017
6018 for pp.runqhead != pp.runqtail {
6019
6020 pp.runqtail--
6021 gp := pp.runq[pp.runqtail%uint32(len(pp.runq))].ptr()
6022
6023 globrunqputhead(gp)
6024 }
6025 if pp.runnext != 0 {
6026 globrunqputhead(pp.runnext.ptr())
6027 pp.runnext = 0
6028 }
6029
6030
6031 getg().m.p.ptr().timers.take(&pp.timers)
6032
6033
6034
6035 if phase := gcphase; phase != _GCoff {
6036 println("runtime: p id", pp.id, "destroyed during GC phase", phase)
6037 throw("P destroyed while GC is running")
6038 }
6039
6040 pp.gcw.spanq.destroy()
6041
6042 clear(pp.waitingGBuf[:])
6043 pp.waitingGCache = pp.waitingGBuf[:0]
6044 pp.pinnerCache = nil
6045 if pp.pinCounterCache != nil {
6046 lock(&mheap_.speciallock)
6047 mheap_.specialPinCounterAlloc.free(unsafe.Pointer(pp.pinCounterCache))
6048 unlock(&mheap_.speciallock)
6049 pp.pinCounterCache = nil
6050 }
6051 clear(pp.deferpoolbuf[:])
6052 pp.deferpool = pp.deferpoolbuf[:0]
6053 systemstack(func() {
6054 for i := 0; i < pp.mspancache.len; i++ {
6055
6056 mheap_.spanalloc.free(unsafe.Pointer(pp.mspancache.buf[i]))
6057 }
6058 pp.mspancache.len = 0
6059 lock(&mheap_.lock)
6060 pp.pcache.flush(&mheap_.pages)
6061 unlock(&mheap_.lock)
6062 })
6063 freemcache(pp.mcache)
6064 pp.mcache = nil
6065 gfpurge(pp)
6066 if raceenabled {
6067 if pp.timers.raceCtx != 0 {
6068
6069
6070
6071
6072
6073 mp := getg().m
6074 phold := mp.p.ptr()
6075 mp.p.set(pp)
6076
6077 racectxend(pp.timers.raceCtx)
6078 pp.timers.raceCtx = 0
6079
6080 mp.p.set(phold)
6081 }
6082 raceprocdestroy(pp.raceprocctx)
6083 pp.raceprocctx = 0
6084 }
6085 pp.gcAssistTime = 0
6086 gcCleanups.queued += pp.cleanupsQueued
6087 pp.cleanupsQueued = 0
6088 sched.goroutinesCreated.Add(int64(pp.goroutinesCreated))
6089 pp.goroutinesCreated = 0
6090 pp.xRegs.free()
6091 pp.status = _Pdead
6092 }
6093
6094
6095
6096
6097
6098
6099
6100
6101
6102 func procresize(nprocs int32) *p {
6103 assertLockHeld(&sched.lock)
6104 assertWorldStopped()
6105
6106 old := gomaxprocs
6107 if old < 0 || nprocs <= 0 {
6108 throw("procresize: invalid arg")
6109 }
6110 trace := traceAcquire()
6111 if trace.ok() {
6112 trace.Gomaxprocs(nprocs)
6113 traceRelease(trace)
6114 }
6115
6116
6117 now := nanotime()
6118 if sched.procresizetime != 0 {
6119 sched.totaltime += int64(old) * (now - sched.procresizetime)
6120 }
6121 sched.procresizetime = now
6122
6123
6124 if nprocs > int32(len(allp)) {
6125
6126
6127 lock(&allpLock)
6128 if nprocs <= int32(cap(allp)) {
6129 allp = allp[:nprocs]
6130 } else {
6131 nallp := make([]*p, nprocs)
6132
6133
6134 copy(nallp, allp[:cap(allp)])
6135 allp = nallp
6136 }
6137
6138 idlepMask = idlepMask.resize(nprocs)
6139 timerpMask = timerpMask.resize(nprocs)
6140 work.spanqMask = work.spanqMask.resize(nprocs)
6141 unlock(&allpLock)
6142 }
6143
6144
6145 for i := old; i < nprocs; i++ {
6146 pp := allp[i]
6147 if pp == nil {
6148 pp = new(p)
6149 }
6150 pp.init(i)
6151 atomicstorep(unsafe.Pointer(&allp[i]), unsafe.Pointer(pp))
6152 }
6153
6154 gp := getg()
6155 if gp.m.p != 0 && gp.m.p.ptr().id < nprocs {
6156
6157 gp.m.p.ptr().status = _Prunning
6158 gp.m.p.ptr().mcache.prepareForSweep()
6159 } else {
6160
6161
6162
6163
6164
6165 if gp.m.p != 0 {
6166 trace := traceAcquire()
6167 if trace.ok() {
6168
6169
6170
6171 trace.GoSched()
6172 trace.ProcStop(gp.m.p.ptr())
6173 traceRelease(trace)
6174 }
6175 gp.m.p.ptr().m = 0
6176 }
6177 gp.m.p = 0
6178 pp := allp[0]
6179 pp.m = 0
6180 pp.status = _Pidle
6181 acquirep(pp)
6182 trace := traceAcquire()
6183 if trace.ok() {
6184 trace.GoStart()
6185 traceRelease(trace)
6186 }
6187 }
6188
6189
6190 mcache0 = nil
6191
6192
6193 for i := nprocs; i < old; i++ {
6194 pp := allp[i]
6195 pp.destroy()
6196
6197 }
6198
6199
6200 if int32(len(allp)) != nprocs {
6201 lock(&allpLock)
6202 allp = allp[:nprocs]
6203 idlepMask = idlepMask.resize(nprocs)
6204 timerpMask = timerpMask.resize(nprocs)
6205 work.spanqMask = work.spanqMask.resize(nprocs)
6206 unlock(&allpLock)
6207 }
6208
6209
6210 var runnablePs *p
6211 var runnablePsNeedM *p
6212 var idlePs *p
6213 for i := nprocs - 1; i >= 0; i-- {
6214 pp := allp[i]
6215 if gp.m.p.ptr() == pp {
6216 continue
6217 }
6218 pp.status = _Pidle
6219 if runqempty(pp) {
6220 pp.link.set(idlePs)
6221 idlePs = pp
6222 continue
6223 }
6224
6225
6226
6227
6228
6229
6230
6231
6232 var mp *m
6233 if oldm := pp.oldm.get(); oldm != nil {
6234
6235 mp = mgetSpecific(oldm)
6236 }
6237 if mp == nil {
6238
6239 pp.link.set(runnablePsNeedM)
6240 runnablePsNeedM = pp
6241 continue
6242 }
6243 pp.m.set(mp)
6244 pp.link.set(runnablePs)
6245 runnablePs = pp
6246 }
6247
6248
6249 for runnablePsNeedM != nil {
6250 pp := runnablePsNeedM
6251 runnablePsNeedM = pp.link.ptr()
6252
6253 mp := mget()
6254 pp.m.set(mp)
6255 pp.link.set(runnablePs)
6256 runnablePs = pp
6257 }
6258
6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
6269
6270
6271
6272
6273
6274
6275
6276
6277
6278
6279
6280
6281
6282
6283 if gcBlackenEnabled != 0 {
6284 for idlePs != nil {
6285 pp := idlePs
6286
6287 ok, _ := gcController.assignWaitingGCWorker(pp, now)
6288 if !ok {
6289
6290 break
6291 }
6292
6293
6294
6295
6296
6297
6298
6299
6300 idlePs = pp.link.ptr()
6301 mp := mget()
6302 pp.m.set(mp)
6303 pp.link.set(runnablePs)
6304 runnablePs = pp
6305 }
6306 }
6307
6308
6309 for idlePs != nil {
6310 pp := idlePs
6311 idlePs = pp.link.ptr()
6312 pidleput(pp, now)
6313 }
6314
6315 stealOrder.reset(uint32(nprocs))
6316 var int32p *int32 = &gomaxprocs
6317 atomic.Store((*uint32)(unsafe.Pointer(int32p)), uint32(nprocs))
6318 if old != nprocs {
6319
6320 gcCPULimiter.resetCapacity(now, nprocs)
6321 }
6322 return runnablePs
6323 }
6324
6325
6326
6327
6328
6329
6330
6331 func acquirep(pp *p) {
6332
6333 acquirepNoTrace(pp)
6334
6335
6336 trace := traceAcquire()
6337 if trace.ok() {
6338 trace.ProcStart()
6339 traceRelease(trace)
6340 }
6341 }
6342
6343
6344
6345
6346 func acquirepNoTrace(pp *p) {
6347
6348 wirep(pp)
6349
6350
6351
6352
6353
6354
6355 pp.oldm = pp.m.ptr().self
6356
6357
6358
6359 pp.mcache.prepareForSweep()
6360 }
6361
6362
6363
6364
6365
6366
6367
6368 func wirep(pp *p) {
6369 gp := getg()
6370
6371 if gp.m.p != 0 {
6372
6373
6374 systemstack(func() {
6375 throw("wirep: already in go")
6376 })
6377 }
6378 if pp.m != 0 || pp.status != _Pidle {
6379
6380
6381 systemstack(func() {
6382 id := int64(0)
6383 if pp.m != 0 {
6384 id = pp.m.ptr().id
6385 }
6386 print("wirep: p->m=", pp.m, "(", id, ") p->status=", pp.status, "\n")
6387 throw("wirep: invalid p state")
6388 })
6389 }
6390 gp.m.p.set(pp)
6391 pp.m.set(gp.m)
6392 pp.status = _Prunning
6393 }
6394
6395
6396 func releasep() *p {
6397 trace := traceAcquire()
6398 if trace.ok() {
6399 trace.ProcStop(getg().m.p.ptr())
6400 traceRelease(trace)
6401 }
6402 return releasepNoTrace()
6403 }
6404
6405
6406 func releasepNoTrace() *p {
6407 gp := getg()
6408
6409 if gp.m.p == 0 {
6410 throw("releasep: invalid arg")
6411 }
6412 pp := gp.m.p.ptr()
6413 if pp.m.ptr() != gp.m || pp.status != _Prunning {
6414 print("releasep: m=", gp.m, " m->p=", gp.m.p.ptr(), " p->m=", hex(pp.m), " p->status=", pp.status, "\n")
6415 throw("releasep: invalid p state")
6416 }
6417
6418
6419 gcController.releaseNextGCMarkWorker(pp)
6420
6421 gp.m.p = 0
6422 pp.m = 0
6423 pp.status = _Pidle
6424 return pp
6425 }
6426
6427 func incidlelocked(v int32) {
6428 lock(&sched.lock)
6429 sched.nmidlelocked += v
6430 if v > 0 {
6431 checkdead()
6432 }
6433 unlock(&sched.lock)
6434 }
6435
6436
6437
6438
6439 func checkdead() {
6440 assertLockHeld(&sched.lock)
6441
6442
6443
6444
6445
6446
6447 if (islibrary || isarchive) && GOARCH != "wasm" {
6448 return
6449 }
6450
6451
6452
6453
6454
6455 if panicking.Load() > 0 {
6456 return
6457 }
6458
6459
6460
6461
6462
6463 var run0 int32
6464 if !iscgo && cgoHasExtraM && extraMLength.Load() > 0 {
6465 run0 = 1
6466 }
6467
6468 run := mcount() - sched.nmidle - sched.nmidlelocked - sched.nmsys
6469 if run > run0 {
6470 return
6471 }
6472 if run < 0 {
6473 print("runtime: checkdead: nmidle=", sched.nmidle, " nmidlelocked=", sched.nmidlelocked, " mcount=", mcount(), " nmsys=", sched.nmsys, "\n")
6474 unlock(&sched.lock)
6475 throw("checkdead: inconsistent counts")
6476 }
6477
6478 grunning := 0
6479 forEachG(func(gp *g) {
6480 if isSystemGoroutine(gp, false) {
6481 return
6482 }
6483 s := readgstatus(gp)
6484 switch s &^ _Gscan {
6485 case _Gwaiting,
6486 _Gpreempted:
6487 grunning++
6488 case _Grunnable,
6489 _Grunning,
6490 _Gsyscall:
6491 print("runtime: checkdead: find g ", gp.goid, " in status ", s, "\n")
6492 unlock(&sched.lock)
6493 throw("checkdead: runnable g")
6494 }
6495 })
6496 if grunning == 0 {
6497 unlock(&sched.lock)
6498 fatal("no goroutines (main called runtime.Goexit) - deadlock!")
6499 }
6500
6501
6502 if faketime != 0 {
6503 if when := timeSleepUntil(); when < maxWhen {
6504 faketime = when
6505
6506
6507 pp, _ := pidleget(faketime)
6508 if pp == nil {
6509
6510
6511 unlock(&sched.lock)
6512 throw("checkdead: no p for timer")
6513 }
6514 mp := mget()
6515 if mp == nil {
6516
6517
6518 unlock(&sched.lock)
6519 throw("checkdead: no m for timer")
6520 }
6521
6522
6523
6524 sched.nmspinning.Add(1)
6525 mp.spinning = true
6526 mp.nextp.set(pp)
6527 notewakeup(&mp.park)
6528 return
6529 }
6530 }
6531
6532
6533 for _, pp := range allp {
6534 if len(pp.timers.heap) > 0 {
6535 return
6536 }
6537 }
6538
6539 unlock(&sched.lock)
6540 fatal("all goroutines are asleep - deadlock!")
6541 }
6542
6543
6544
6545
6546
6547
6548 var forcegcperiod int64 = 2 * 60 * 1e9
6549
6550
6551
6552
6553 const haveSysmon = GOARCH != "wasm"
6554
6555
6556
6557
6558 func sysmon() {
6559 lock(&sched.lock)
6560 sched.nmsys++
6561 checkdead()
6562 unlock(&sched.lock)
6563
6564 lastgomaxprocs := int64(0)
6565 lasttrace := int64(0)
6566 idle := 0
6567 delay := uint32(0)
6568
6569 for {
6570 if idle == 0 {
6571 delay = 20
6572 } else if idle > 50 {
6573 delay *= 2
6574 }
6575 if delay > 10*1000 {
6576 delay = 10 * 1000
6577 }
6578 usleep(delay)
6579
6580
6581
6582
6583
6584
6585
6586
6587
6588
6589
6590
6591
6592
6593
6594
6595 now := nanotime()
6596 if debug.schedtrace <= 0 && (sched.gcwaiting.Load() || sched.npidle.Load() == gomaxprocs) {
6597 lock(&sched.lock)
6598 if sched.gcwaiting.Load() || sched.npidle.Load() == gomaxprocs {
6599 syscallWake := false
6600 next := timeSleepUntil()
6601 if next > now {
6602 sched.sysmonwait.Store(true)
6603 unlock(&sched.lock)
6604
6605
6606 sleep := forcegcperiod / 2
6607 if next-now < sleep {
6608 sleep = next - now
6609 }
6610 shouldRelax := sleep >= osRelaxMinNS
6611 if shouldRelax {
6612 osRelax(true)
6613 }
6614 syscallWake = notetsleep(&sched.sysmonnote, sleep)
6615 if shouldRelax {
6616 osRelax(false)
6617 }
6618 lock(&sched.lock)
6619 sched.sysmonwait.Store(false)
6620 noteclear(&sched.sysmonnote)
6621 }
6622 if syscallWake {
6623 idle = 0
6624 delay = 20
6625 }
6626 }
6627 unlock(&sched.lock)
6628 }
6629
6630 lock(&sched.sysmonlock)
6631
6632
6633 now = nanotime()
6634
6635
6636 if *cgo_yield != nil {
6637 asmcgocall(*cgo_yield, nil)
6638 }
6639
6640 lastpoll := sched.lastpoll.Load()
6641 if netpollinited() && lastpoll != 0 && lastpoll+10*1000*1000 < now {
6642 sched.lastpoll.CompareAndSwap(lastpoll, now)
6643 list, delta := netpoll(0)
6644 if !list.empty() {
6645
6646
6647
6648
6649
6650
6651
6652 incidlelocked(-1)
6653 injectglist(&list)
6654 incidlelocked(1)
6655 netpollAdjustWaiters(delta)
6656 }
6657 }
6658
6659 if debug.updatemaxprocs != 0 && lastgomaxprocs+1e9 <= now {
6660 sysmonUpdateGOMAXPROCS()
6661 lastgomaxprocs = now
6662 }
6663 if scavenger.sysmonWake.Load() != 0 {
6664
6665 scavenger.wake()
6666 }
6667
6668
6669 if retake(now) != 0 {
6670 idle = 0
6671 } else {
6672 idle++
6673 }
6674
6675 if t := (gcTrigger{kind: gcTriggerTime, now: now}); t.test() && forcegc.idle.Load() {
6676 lock(&forcegc.lock)
6677 forcegc.idle.Store(false)
6678 var list gList
6679 list.push(forcegc.g)
6680 injectglist(&list)
6681 unlock(&forcegc.lock)
6682 }
6683 if debug.schedtrace > 0 && lasttrace+int64(debug.schedtrace)*1000000 <= now {
6684 lasttrace = now
6685 schedtrace(debug.scheddetail > 0)
6686 }
6687 unlock(&sched.sysmonlock)
6688 }
6689 }
6690
6691 type sysmontick struct {
6692 schedtick uint32
6693 syscalltick uint32
6694 schedwhen int64
6695 syscallwhen int64
6696 }
6697
6698
6699
6700 const forcePreemptNS = 10 * 1000 * 1000
6701
6702 func retake(now int64) uint32 {
6703 n := 0
6704
6705
6706 lock(&allpLock)
6707
6708
6709
6710 for i := 0; i < len(allp); i++ {
6711
6712
6713
6714
6715
6716
6717
6718
6719 pp := allp[i]
6720 if pp == nil || atomic.Load(&pp.status) != _Prunning {
6721
6722
6723 continue
6724 }
6725 pd := &pp.sysmontick
6726 sysretake := false
6727
6728
6729
6730
6731
6732 schedt := int64(pp.schedtick)
6733 if int64(pd.schedtick) != schedt {
6734 pd.schedtick = uint32(schedt)
6735 pd.schedwhen = now
6736 } else if pd.schedwhen+forcePreemptNS <= now {
6737 preemptone(pp)
6738
6739
6740
6741
6742 sysretake = true
6743 }
6744
6745
6746 unlock(&allpLock)
6747
6748
6749
6750
6751
6752
6753
6754
6755 incidlelocked(-1)
6756
6757
6758 thread, ok := setBlockOnExitSyscall(pp)
6759 if !ok {
6760
6761 goto done
6762 }
6763
6764
6765 if syst := int64(pp.syscalltick); !sysretake && int64(pd.syscalltick) != syst {
6766 pd.syscalltick = uint32(syst)
6767 pd.syscallwhen = now
6768 thread.resume()
6769 goto done
6770 }
6771
6772
6773
6774
6775 if runqempty(pp) && sched.nmspinning.Load()+sched.npidle.Load() > 0 && pd.syscallwhen+10*1000*1000 > now {
6776 thread.resume()
6777 goto done
6778 }
6779
6780
6781
6782 thread.takeP()
6783 thread.resume()
6784 n++
6785
6786
6787 handoffp(pp)
6788
6789
6790
6791 done:
6792 incidlelocked(1)
6793 lock(&allpLock)
6794 }
6795 unlock(&allpLock)
6796 return uint32(n)
6797 }
6798
6799
6800
6801 type syscallingThread struct {
6802 gp *g
6803 mp *m
6804 pp *p
6805 status uint32
6806 }
6807
6808
6809
6810
6811
6812
6813
6814
6815
6816
6817
6818
6819
6820
6821
6822 func setBlockOnExitSyscall(pp *p) (syscallingThread, bool) {
6823 if pp.status != _Prunning {
6824 return syscallingThread{}, false
6825 }
6826
6827
6828
6829
6830
6831
6832
6833
6834
6835
6836
6837 mp := pp.m.ptr()
6838 if mp == nil {
6839
6840 return syscallingThread{}, false
6841 }
6842 gp := mp.curg
6843 if gp == nil {
6844
6845 return syscallingThread{}, false
6846 }
6847 status := readgstatus(gp) &^ _Gscan
6848
6849
6850
6851
6852 if status != _Gsyscall && status != _Gdeadextra {
6853
6854 return syscallingThread{}, false
6855 }
6856 if !castogscanstatus(gp, status, status|_Gscan) {
6857
6858 return syscallingThread{}, false
6859 }
6860 if gp.m != mp || gp.m.p.ptr() != pp {
6861
6862 casfrom_Gscanstatus(gp, status|_Gscan, status)
6863 return syscallingThread{}, false
6864 }
6865 return syscallingThread{gp, mp, pp, status}, true
6866 }
6867
6868
6869
6870
6871
6872 func (s syscallingThread) gcstopP() {
6873 assertLockHeld(&sched.lock)
6874
6875 s.releaseP(_Pgcstop)
6876 s.pp.gcStopTime = nanotime()
6877 sched.stopwait--
6878 }
6879
6880
6881
6882 func (s syscallingThread) takeP() {
6883 s.releaseP(_Pidle)
6884 }
6885
6886
6887
6888
6889 func (s syscallingThread) releaseP(state uint32) {
6890 if state != _Pidle && state != _Pgcstop {
6891 throw("attempted to release P into a bad state")
6892 }
6893 trace := traceAcquire()
6894 s.pp.m = 0
6895 s.mp.p = 0
6896 atomic.Store(&s.pp.status, state)
6897 if trace.ok() {
6898 trace.ProcSteal(s.pp)
6899 traceRelease(trace)
6900 }
6901 addGSyscallNoP(s.mp)
6902 s.pp.syscalltick++
6903 }
6904
6905
6906 func (s syscallingThread) resume() {
6907 casfrom_Gscanstatus(s.gp, s.status|_Gscan, s.status)
6908 }
6909
6910
6911
6912
6913
6914
6915 func preemptall() bool {
6916 res := false
6917 for _, pp := range allp {
6918 if pp.status != _Prunning {
6919 continue
6920 }
6921 if preemptone(pp) {
6922 res = true
6923 }
6924 }
6925 return res
6926 }
6927
6928
6929
6930
6931
6932
6933
6934
6935
6936
6937
6938 func preemptone(pp *p) bool {
6939 mp := pp.m.ptr()
6940 if mp == nil || mp == getg().m {
6941 return false
6942 }
6943 gp := mp.curg
6944 if gp == nil || gp == mp.g0 {
6945 return false
6946 }
6947 if readgstatus(gp)&^_Gscan == _Gsyscall {
6948
6949 return false
6950 }
6951
6952 gp.preempt = true
6953
6954
6955
6956
6957
6958 gp.stackguard0 = stackPreempt
6959
6960
6961 if preemptMSupported && debug.asyncpreemptoff == 0 {
6962 pp.preempt = true
6963
6964
6965 if castogscanstatus(gp, _Grunning, _Gscanrunning) {
6966 if gp.m == mp {
6967 preemptM(gp)
6968 } else {
6969 casfrom_Gscanstatus(gp, _Gscanrunning, _Grunning)
6970 }
6971 }
6972 }
6973
6974 return true
6975 }
6976
6977 var starttime int64
6978
6979 func schedtrace(detailed bool) {
6980 now := nanotime()
6981 if starttime == 0 {
6982 starttime = now
6983 }
6984
6985 lock(&sched.lock)
6986 print("SCHED ", (now-starttime)/1e6, "ms: gomaxprocs=", gomaxprocs, " idleprocs=", sched.npidle.Load(), " threads=", mcount(), " spinningthreads=", sched.nmspinning.Load(), " needspinning=", sched.needspinning.Load(), " idlethreads=", sched.nmidle, " runqueue=", sched.runq.size)
6987 if detailed {
6988 print(" gcwaiting=", sched.gcwaiting.Load(), " nmidlelocked=", sched.nmidlelocked, " stopwait=", sched.stopwait, " sysmonwait=", sched.sysmonwait.Load(), "\n")
6989 }
6990
6991
6992
6993 for i, pp := range allp {
6994 h := atomic.Load(&pp.runqhead)
6995 t := atomic.Load(&pp.runqtail)
6996 if detailed {
6997 print(" P", i, ": status=", pp.status, " schedtick=", pp.schedtick, " syscalltick=", pp.syscalltick, " m=")
6998 mp := pp.m.ptr()
6999 if mp != nil {
7000 print(mp.id)
7001 } else {
7002 print("nil")
7003 }
7004 print(" runqsize=", t-h, " gfreecnt=", pp.gFree.size, " timerslen=", len(pp.timers.heap), "\n")
7005 } else {
7006
7007
7008 print(" ")
7009 if i == 0 {
7010 print("[ ")
7011 }
7012 print(t - h)
7013 if i == len(allp)-1 {
7014 print(" ]")
7015 }
7016 }
7017 }
7018
7019 if !detailed {
7020
7021 print(" schedticks=[ ")
7022 for _, pp := range allp {
7023 print(pp.schedtick)
7024 print(" ")
7025 }
7026 print("]\n")
7027 }
7028
7029 if !detailed {
7030 unlock(&sched.lock)
7031 return
7032 }
7033
7034 for mp := allm; mp != nil; mp = mp.alllink {
7035 pp := mp.p.ptr()
7036 print(" M", mp.id, ": p=")
7037 if pp != nil {
7038 print(pp.id)
7039 } else {
7040 print("nil")
7041 }
7042 print(" curg=")
7043 if mp.curg != nil {
7044 print(mp.curg.goid)
7045 } else {
7046 print("nil")
7047 }
7048 print(" mallocing=", mp.mallocing, " throwing=", mp.throwing, " preemptoff=", mp.preemptoff, " locks=", mp.locks, " dying=", mp.dying, " spinning=", mp.spinning, " blocked=", mp.blocked, " lockedg=")
7049 if lockedg := mp.lockedg.ptr(); lockedg != nil {
7050 print(lockedg.goid)
7051 } else {
7052 print("nil")
7053 }
7054 print("\n")
7055 }
7056
7057 forEachG(func(gp *g) {
7058 print(" G", gp.goid, ": status=", readgstatus(gp), "(", gp.waitreason.String(), ") m=")
7059 if gp.m != nil {
7060 print(gp.m.id)
7061 } else {
7062 print("nil")
7063 }
7064 print(" lockedm=")
7065 if lockedm := gp.lockedm.ptr(); lockedm != nil {
7066 print(lockedm.id)
7067 } else {
7068 print("nil")
7069 }
7070 print("\n")
7071 })
7072 unlock(&sched.lock)
7073 }
7074
7075 type updateMaxProcsGState struct {
7076 lock mutex
7077 g *g
7078 idle atomic.Bool
7079
7080
7081 procs int32
7082 }
7083
7084 var (
7085
7086
7087 updatemaxprocs = &godebugInc{name: "updatemaxprocs"}
7088
7089
7090
7091 updateMaxProcsG updateMaxProcsGState
7092
7093
7094
7095
7096
7097
7098
7099
7100
7101
7102
7103
7104
7105
7106
7107
7108
7109
7110
7111
7112
7113
7114
7115
7116
7117
7118
7119
7120
7121
7122
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132
7133
7134
7135
7136
7137
7138
7139
7140 computeMaxProcsLock mutex
7141 )
7142
7143
7144
7145
7146 func defaultGOMAXPROCSUpdateEnable() {
7147 if debug.updatemaxprocs == 0 {
7148
7149
7150
7151
7152
7153
7154
7155
7156
7157
7158
7159 updatemaxprocs.IncNonDefault()
7160 return
7161 }
7162
7163 go updateMaxProcsGoroutine()
7164 }
7165
7166 func updateMaxProcsGoroutine() {
7167 updateMaxProcsG.g = getg()
7168 lockInit(&updateMaxProcsG.lock, lockRankUpdateMaxProcsG)
7169 for {
7170 lock(&updateMaxProcsG.lock)
7171 if updateMaxProcsG.idle.Load() {
7172 throw("updateMaxProcsGoroutine: phase error")
7173 }
7174 updateMaxProcsG.idle.Store(true)
7175 goparkunlock(&updateMaxProcsG.lock, waitReasonUpdateGOMAXPROCSIdle, traceBlockSystemGoroutine, 1)
7176
7177
7178 stw := stopTheWorldGC(stwGOMAXPROCS)
7179
7180
7181 lock(&sched.lock)
7182 custom := sched.customGOMAXPROCS
7183 unlock(&sched.lock)
7184 if custom {
7185 startTheWorldGC(stw)
7186 return
7187 }
7188
7189
7190
7191
7192
7193 newprocs = updateMaxProcsG.procs
7194 lock(&sched.lock)
7195 sched.customGOMAXPROCS = false
7196 unlock(&sched.lock)
7197
7198 startTheWorldGC(stw)
7199 }
7200 }
7201
7202 func sysmonUpdateGOMAXPROCS() {
7203
7204 lock(&computeMaxProcsLock)
7205
7206
7207 lock(&sched.lock)
7208 custom := sched.customGOMAXPROCS
7209 curr := gomaxprocs
7210 unlock(&sched.lock)
7211 if custom {
7212 unlock(&computeMaxProcsLock)
7213 return
7214 }
7215
7216
7217 procs := defaultGOMAXPROCS(0)
7218 unlock(&computeMaxProcsLock)
7219 if procs == curr {
7220
7221 return
7222 }
7223
7224
7225
7226
7227 if updateMaxProcsG.idle.Load() {
7228 lock(&updateMaxProcsG.lock)
7229 updateMaxProcsG.procs = procs
7230 updateMaxProcsG.idle.Store(false)
7231 var list gList
7232 list.push(updateMaxProcsG.g)
7233 injectglist(&list)
7234 unlock(&updateMaxProcsG.lock)
7235 }
7236 }
7237
7238
7239
7240
7241
7242
7243 func schedEnableUser(enable bool) {
7244 lock(&sched.lock)
7245 if sched.disable.user == !enable {
7246 unlock(&sched.lock)
7247 return
7248 }
7249 sched.disable.user = !enable
7250 if enable {
7251 n := sched.disable.runnable.size
7252 globrunqputbatch(&sched.disable.runnable)
7253 unlock(&sched.lock)
7254 for ; n != 0 && sched.npidle.Load() != 0; n-- {
7255 startm(nil, false, false)
7256 }
7257 } else {
7258 unlock(&sched.lock)
7259 }
7260 }
7261
7262
7263
7264
7265
7266 func schedEnabled(gp *g) bool {
7267 assertLockHeld(&sched.lock)
7268
7269 if sched.disable.user {
7270 return isSystemGoroutine(gp, true)
7271 }
7272 return true
7273 }
7274
7275
7276
7277
7278
7279
7280 func mput(mp *m) {
7281 assertLockHeld(&sched.lock)
7282
7283 sched.midle.push(unsafe.Pointer(mp))
7284 sched.nmidle++
7285 checkdead()
7286 }
7287
7288
7289
7290
7291
7292
7293 func mget() *m {
7294 assertLockHeld(&sched.lock)
7295
7296 mp := (*m)(sched.midle.pop())
7297 if mp != nil {
7298 sched.nmidle--
7299 }
7300 return mp
7301 }
7302
7303
7304
7305
7306
7307
7308
7309
7310 func mgetSpecific(mp *m) *m {
7311 assertLockHeld(&sched.lock)
7312
7313 if mp.idleNode.prev == 0 && mp.idleNode.next == 0 {
7314
7315 return nil
7316 }
7317
7318 sched.midle.remove(unsafe.Pointer(mp))
7319 sched.nmidle--
7320
7321 return mp
7322 }
7323
7324
7325
7326
7327
7328
7329 func globrunqput(gp *g) {
7330 assertLockHeld(&sched.lock)
7331
7332 sched.runq.pushBack(gp)
7333 }
7334
7335
7336
7337
7338
7339
7340 func globrunqputhead(gp *g) {
7341 assertLockHeld(&sched.lock)
7342
7343 sched.runq.push(gp)
7344 }
7345
7346
7347
7348
7349
7350
7351
7352 func globrunqputbatch(batch *gQueue) {
7353 assertLockHeld(&sched.lock)
7354
7355 sched.runq.pushBackAll(*batch)
7356 *batch = gQueue{}
7357 }
7358
7359
7360
7361 func globrunqget() *g {
7362 assertLockHeld(&sched.lock)
7363
7364 if sched.runq.size == 0 {
7365 return nil
7366 }
7367
7368 return sched.runq.pop()
7369 }
7370
7371
7372
7373 func globrunqgetbatch(n int32) (gp *g, q gQueue) {
7374 assertLockHeld(&sched.lock)
7375
7376 if sched.runq.size == 0 {
7377 return
7378 }
7379
7380 n = min(n, sched.runq.size, sched.runq.size/gomaxprocs+1)
7381
7382 gp = sched.runq.pop()
7383 n--
7384
7385 for ; n > 0; n-- {
7386 gp1 := sched.runq.pop()
7387 q.pushBack(gp1)
7388 }
7389 return
7390 }
7391
7392
7393 type pMask []uint32
7394
7395
7396 func (p pMask) read(id uint32) bool {
7397 word := id / 32
7398 mask := uint32(1) << (id % 32)
7399 return (atomic.Load(&p[word]) & mask) != 0
7400 }
7401
7402
7403 func (p pMask) set(id int32) {
7404 word := id / 32
7405 mask := uint32(1) << (id % 32)
7406 atomic.Or(&p[word], mask)
7407 }
7408
7409
7410 func (p pMask) clear(id int32) {
7411 word := id / 32
7412 mask := uint32(1) << (id % 32)
7413 atomic.And(&p[word], ^mask)
7414 }
7415
7416
7417 func (p pMask) any() bool {
7418 for i := range p {
7419 if atomic.Load(&p[i]) != 0 {
7420 return true
7421 }
7422 }
7423 return false
7424 }
7425
7426
7427
7428
7429
7430 func (p pMask) resize(nprocs int32) pMask {
7431 maskWords := (nprocs + 31) / 32
7432
7433 if maskWords <= int32(cap(p)) {
7434 return p[:maskWords]
7435 }
7436 newMask := make([]uint32, maskWords)
7437
7438 copy(newMask, p)
7439 return newMask
7440 }
7441
7442
7443
7444
7445
7446
7447
7448
7449
7450
7451
7452
7453 func pidleput(pp *p, now int64) int64 {
7454 assertLockHeld(&sched.lock)
7455
7456 if !runqempty(pp) {
7457 throw("pidleput: P has non-empty run queue")
7458 }
7459 if now == 0 {
7460 now = nanotime()
7461 }
7462 if pp.timers.len.Load() == 0 {
7463 timerpMask.clear(pp.id)
7464 }
7465 idlepMask.set(pp.id)
7466 pp.link = sched.pidle
7467 sched.pidle.set(pp)
7468 sched.npidle.Add(1)
7469 if !pp.limiterEvent.start(limiterEventIdle, now) {
7470 throw("must be able to track idle limiter event")
7471 }
7472 return now
7473 }
7474
7475
7476
7477
7478
7479
7480
7481
7482 func pidleget(now int64) (*p, int64) {
7483 assertLockHeld(&sched.lock)
7484
7485 pp := sched.pidle.ptr()
7486 if pp != nil {
7487
7488 if now == 0 {
7489 now = nanotime()
7490 }
7491 timerpMask.set(pp.id)
7492 idlepMask.clear(pp.id)
7493 sched.pidle = pp.link
7494 sched.npidle.Add(-1)
7495 pp.limiterEvent.stop(limiterEventIdle, now)
7496 }
7497 return pp, now
7498 }
7499
7500
7501
7502
7503
7504
7505
7506
7507
7508
7509
7510 func pidlegetSpinning(now int64) (*p, int64) {
7511 assertLockHeld(&sched.lock)
7512
7513 pp, now := pidleget(now)
7514 if pp == nil {
7515
7516
7517
7518 sched.needspinning.Store(1)
7519 return nil, now
7520 }
7521
7522 return pp, now
7523 }
7524
7525
7526
7527 func runqempty(pp *p) bool {
7528
7529
7530
7531
7532 for {
7533 head := atomic.Load(&pp.runqhead)
7534 tail := atomic.Load(&pp.runqtail)
7535 runnext := atomic.Loaduintptr((*uintptr)(unsafe.Pointer(&pp.runnext)))
7536 if tail == atomic.Load(&pp.runqtail) {
7537 return head == tail && runnext == 0
7538 }
7539 }
7540 }
7541
7542
7543
7544
7545
7546
7547
7548
7549
7550
7551 const randomizeScheduler = raceenabled
7552
7553
7554
7555
7556
7557
7558 func runqput(pp *p, gp *g, next bool) {
7559 if !haveSysmon && next {
7560
7561
7562
7563
7564
7565
7566
7567
7568 next = false
7569 }
7570 if randomizeScheduler && next && randn(2) == 0 {
7571 next = false
7572 }
7573
7574 if next {
7575 retryNext:
7576 oldnext := pp.runnext
7577 if !pp.runnext.cas(oldnext, guintptr(unsafe.Pointer(gp))) {
7578 goto retryNext
7579 }
7580 if oldnext == 0 {
7581 return
7582 }
7583
7584 gp = oldnext.ptr()
7585 }
7586
7587 retry:
7588 h := atomic.LoadAcq(&pp.runqhead)
7589 t := pp.runqtail
7590 if t-h < uint32(len(pp.runq)) {
7591 pp.runq[t%uint32(len(pp.runq))].set(gp)
7592 atomic.StoreRel(&pp.runqtail, t+1)
7593 return
7594 }
7595 if runqputslow(pp, gp, h, t) {
7596 return
7597 }
7598
7599 goto retry
7600 }
7601
7602
7603
7604 func runqputslow(pp *p, gp *g, h, t uint32) bool {
7605 var batch [len(pp.runq)/2 + 1]*g
7606
7607
7608 n := t - h
7609 n = n / 2
7610 if n != uint32(len(pp.runq)/2) {
7611 throw("runqputslow: queue is not full")
7612 }
7613 for i := uint32(0); i < n; i++ {
7614 batch[i] = pp.runq[(h+i)%uint32(len(pp.runq))].ptr()
7615 }
7616 if !atomic.CasRel(&pp.runqhead, h, h+n) {
7617 return false
7618 }
7619 batch[n] = gp
7620
7621 if randomizeScheduler {
7622 for i := uint32(1); i <= n; i++ {
7623 j := cheaprandn(i + 1)
7624 batch[i], batch[j] = batch[j], batch[i]
7625 }
7626 }
7627
7628
7629 for i := uint32(0); i < n; i++ {
7630 batch[i].schedlink.set(batch[i+1])
7631 }
7632
7633 q := gQueue{batch[0].guintptr(), batch[n].guintptr(), int32(n + 1)}
7634
7635
7636 lock(&sched.lock)
7637 globrunqputbatch(&q)
7638 unlock(&sched.lock)
7639 return true
7640 }
7641
7642
7643
7644
7645 func runqputbatch(pp *p, q *gQueue) {
7646 if q.empty() {
7647 return
7648 }
7649 h := atomic.LoadAcq(&pp.runqhead)
7650 t := pp.runqtail
7651 n := uint32(0)
7652 for !q.empty() && t-h < uint32(len(pp.runq)) {
7653 gp := q.pop()
7654 pp.runq[t%uint32(len(pp.runq))].set(gp)
7655 t++
7656 n++
7657 }
7658
7659 if randomizeScheduler {
7660 off := func(o uint32) uint32 {
7661 return (pp.runqtail + o) % uint32(len(pp.runq))
7662 }
7663 for i := uint32(1); i < n; i++ {
7664 j := cheaprandn(i + 1)
7665 pp.runq[off(i)], pp.runq[off(j)] = pp.runq[off(j)], pp.runq[off(i)]
7666 }
7667 }
7668
7669 atomic.StoreRel(&pp.runqtail, t)
7670
7671 return
7672 }
7673
7674
7675
7676
7677
7678 func runqget(pp *p) (gp *g, inheritTime bool) {
7679
7680 next := pp.runnext
7681
7682
7683
7684 if next != 0 && pp.runnext.cas(next, 0) {
7685 return next.ptr(), true
7686 }
7687
7688 for {
7689 h := atomic.LoadAcq(&pp.runqhead)
7690 t := pp.runqtail
7691 if t == h {
7692 return nil, false
7693 }
7694 gp := pp.runq[h%uint32(len(pp.runq))].ptr()
7695 if atomic.CasRel(&pp.runqhead, h, h+1) {
7696 return gp, false
7697 }
7698 }
7699 }
7700
7701
7702
7703 func runqdrain(pp *p) (drainQ gQueue) {
7704 oldNext := pp.runnext
7705 if oldNext != 0 && pp.runnext.cas(oldNext, 0) {
7706 drainQ.pushBack(oldNext.ptr())
7707 }
7708
7709 retry:
7710 h := atomic.LoadAcq(&pp.runqhead)
7711 t := pp.runqtail
7712 qn := t - h
7713 if qn == 0 {
7714 return
7715 }
7716 if qn > uint32(len(pp.runq)) {
7717 goto retry
7718 }
7719
7720 if !atomic.CasRel(&pp.runqhead, h, h+qn) {
7721 goto retry
7722 }
7723
7724
7725
7726
7727
7728
7729
7730
7731 for i := uint32(0); i < qn; i++ {
7732 gp := pp.runq[(h+i)%uint32(len(pp.runq))].ptr()
7733 drainQ.pushBack(gp)
7734 }
7735 return
7736 }
7737
7738
7739
7740
7741
7742 func runqgrab(pp *p, batch *[256]guintptr, batchHead uint32, stealRunNextG bool) uint32 {
7743 for {
7744 h := atomic.LoadAcq(&pp.runqhead)
7745 t := atomic.LoadAcq(&pp.runqtail)
7746 n := t - h
7747 n = n - n/2
7748 if n == 0 {
7749 if stealRunNextG {
7750
7751 if next := pp.runnext; next != 0 {
7752 if pp.status == _Prunning {
7753 if mp := pp.m.ptr(); mp != nil {
7754 if gp := mp.curg; gp == nil || readgstatus(gp)&^_Gscan != _Gsyscall {
7755
7756
7757
7758
7759
7760
7761
7762
7763
7764
7765
7766
7767
7768
7769
7770
7771
7772
7773
7774 stealRunnextSleep(3000)
7775 if sched.gcwaiting.Load() {
7776
7777
7778 return 0
7779 }
7780 }
7781 }
7782 }
7783 if !pp.runnext.cas(next, 0) {
7784 continue
7785 }
7786 batch[batchHead%uint32(len(batch))] = next
7787 return 1
7788 }
7789 }
7790 return 0
7791 }
7792 if n > uint32(len(pp.runq)/2) {
7793 continue
7794 }
7795 for i := uint32(0); i < n; i++ {
7796 g := pp.runq[(h+i)%uint32(len(pp.runq))]
7797 batch[(batchHead+i)%uint32(len(batch))] = g
7798 }
7799 if atomic.CasRel(&pp.runqhead, h, h+n) {
7800 return n
7801 }
7802 }
7803 }
7804
7805
7806
7807
7808 func runqsteal(pp, p2 *p, stealRunNextG bool) *g {
7809 t := pp.runqtail
7810 n := runqgrab(p2, &pp.runq, t, stealRunNextG)
7811 if n == 0 {
7812 return nil
7813 }
7814 n--
7815 gp := pp.runq[(t+n)%uint32(len(pp.runq))].ptr()
7816 if n == 0 {
7817 return gp
7818 }
7819 h := atomic.LoadAcq(&pp.runqhead)
7820 if t-h+n >= uint32(len(pp.runq)) {
7821 throw("runqsteal: runq overflow")
7822 }
7823 atomic.StoreRel(&pp.runqtail, t+n)
7824 return gp
7825 }
7826
7827
7828
7829 type gQueue struct {
7830 head guintptr
7831 tail guintptr
7832 size int32
7833 }
7834
7835
7836 func (q *gQueue) empty() bool {
7837 return q.head == 0
7838 }
7839
7840
7841 func (q *gQueue) push(gp *g) {
7842 gp.schedlink = q.head
7843 q.head.set(gp)
7844 if q.tail == 0 {
7845 q.tail.set(gp)
7846 }
7847 q.size++
7848 }
7849
7850
7851 func (q *gQueue) pushBack(gp *g) {
7852 gp.schedlink = 0
7853 if q.tail != 0 {
7854 q.tail.ptr().schedlink.set(gp)
7855 } else {
7856 q.head.set(gp)
7857 }
7858 q.tail.set(gp)
7859 q.size++
7860 }
7861
7862
7863
7864 func (q *gQueue) pushBackAll(q2 gQueue) {
7865 if q2.tail == 0 {
7866 return
7867 }
7868 q2.tail.ptr().schedlink = 0
7869 if q.tail != 0 {
7870 q.tail.ptr().schedlink = q2.head
7871 } else {
7872 q.head = q2.head
7873 }
7874 q.tail = q2.tail
7875 q.size += q2.size
7876 }
7877
7878
7879
7880 func (q *gQueue) pop() *g {
7881 gp := q.head.ptr()
7882 if gp != nil {
7883 q.head = gp.schedlink
7884 if q.head == 0 {
7885 q.tail = 0
7886 }
7887 q.size--
7888 }
7889 return gp
7890 }
7891
7892
7893 func (q *gQueue) popList() gList {
7894 stack := gList{q.head, q.size}
7895 *q = gQueue{}
7896 return stack
7897 }
7898
7899
7900
7901 type gList struct {
7902 head guintptr
7903 size int32
7904 }
7905
7906
7907 func (l *gList) empty() bool {
7908 return l.head == 0
7909 }
7910
7911
7912 func (l *gList) push(gp *g) {
7913 gp.schedlink = l.head
7914 l.head.set(gp)
7915 l.size++
7916 }
7917
7918
7919 func (l *gList) pushAll(q gQueue) {
7920 if !q.empty() {
7921 q.tail.ptr().schedlink = l.head
7922 l.head = q.head
7923 l.size += q.size
7924 }
7925 }
7926
7927
7928 func (l *gList) pop() *g {
7929 gp := l.head.ptr()
7930 if gp != nil {
7931 l.head = gp.schedlink
7932 l.size--
7933 }
7934 return gp
7935 }
7936
7937
7938 func setMaxThreads(in int) (out int) {
7939 lock(&sched.lock)
7940 out = int(sched.maxmcount)
7941 if in > 0x7fffffff {
7942 sched.maxmcount = 0x7fffffff
7943 } else {
7944 sched.maxmcount = int32(in)
7945 }
7946 checkmcount()
7947 unlock(&sched.lock)
7948 return
7949 }
7950
7951
7952
7953
7954
7955
7956
7957
7958
7959
7960
7961
7962
7963 func procPin() int {
7964 gp := getg()
7965 mp := gp.m
7966
7967 mp.locks++
7968 return int(mp.p.ptr().id)
7969 }
7970
7971
7972
7973
7974
7975
7976
7977
7978
7979
7980
7981
7982
7983 func procUnpin() {
7984 gp := getg()
7985 gp.m.locks--
7986 }
7987
7988
7989
7990 func sync_runtime_procPin() int {
7991 return procPin()
7992 }
7993
7994
7995
7996 func sync_runtime_procUnpin() {
7997 procUnpin()
7998 }
7999
8000
8001
8002 func sync_atomic_runtime_procPin() int {
8003 return procPin()
8004 }
8005
8006
8007
8008 func sync_atomic_runtime_procUnpin() {
8009 procUnpin()
8010 }
8011
8012
8013
8014
8015
8016 func internal_sync_runtime_canSpin(i int) bool {
8017
8018
8019
8020
8021
8022 if i >= active_spin || numCPUStartup <= 1 || gomaxprocs <= sched.npidle.Load()+sched.nmspinning.Load()+1 {
8023 return false
8024 }
8025 if p := getg().m.p.ptr(); !runqempty(p) {
8026 return false
8027 }
8028 return true
8029 }
8030
8031
8032
8033 func internal_sync_runtime_doSpin() {
8034 procyield(active_spin_cnt)
8035 }
8036
8037
8038
8039
8040
8041
8042
8043
8044
8045
8046
8047
8048
8049
8050
8051 func sync_runtime_canSpin(i int) bool {
8052 return internal_sync_runtime_canSpin(i)
8053 }
8054
8055
8056
8057
8058
8059
8060
8061
8062
8063
8064
8065
8066
8067 func sync_runtime_doSpin() {
8068 internal_sync_runtime_doSpin()
8069 }
8070
8071 var stealOrder randomOrder
8072
8073
8074
8075
8076
8077 type randomOrder struct {
8078 count uint32
8079 coprimes []uint32
8080 }
8081
8082 type randomEnum struct {
8083 i uint32
8084 count uint32
8085 pos uint32
8086 inc uint32
8087 }
8088
8089 func (ord *randomOrder) reset(count uint32) {
8090 ord.count = count
8091 ord.coprimes = ord.coprimes[:0]
8092 for i := uint32(1); i <= count; i++ {
8093 if gcd(i, count) == 1 {
8094 ord.coprimes = append(ord.coprimes, i)
8095 }
8096 }
8097 }
8098
8099 func (ord *randomOrder) start(i uint32) randomEnum {
8100 return randomEnum{
8101 count: ord.count,
8102 pos: i % ord.count,
8103 inc: ord.coprimes[i/ord.count%uint32(len(ord.coprimes))],
8104 }
8105 }
8106
8107 func (enum *randomEnum) done() bool {
8108 return enum.i == enum.count
8109 }
8110
8111 func (enum *randomEnum) next() {
8112 enum.i++
8113 enum.pos = (enum.pos + enum.inc) % enum.count
8114 }
8115
8116 func (enum *randomEnum) position() uint32 {
8117 return enum.pos
8118 }
8119
8120 func gcd(a, b uint32) uint32 {
8121 for b != 0 {
8122 a, b = b, a%b
8123 }
8124 return a
8125 }
8126
8127
8128
8129 type initTask struct {
8130 state uint32
8131 nfns uint32
8132
8133 }
8134
8135
8136
8137 var inittrace tracestat
8138
8139 type tracestat struct {
8140 active bool
8141 id uint64
8142 allocs uint64
8143 bytes uint64
8144 }
8145
8146 func doInit(ts []*initTask) {
8147 for _, t := range ts {
8148 doInit1(t)
8149 }
8150 }
8151
8152 func doInit1(t *initTask) {
8153 switch t.state {
8154 case 2:
8155 return
8156 case 1:
8157 throw("recursive call during initialization - linker skew")
8158 default:
8159 t.state = 1
8160
8161 var (
8162 start int64
8163 before tracestat
8164 )
8165
8166 if inittrace.active {
8167 start = nanotime()
8168
8169 before = inittrace
8170 }
8171
8172 if t.nfns == 0 {
8173
8174 throw("inittask with no functions")
8175 }
8176
8177 firstFunc := add(unsafe.Pointer(t), 8)
8178 for i := uint32(0); i < t.nfns; i++ {
8179 p := add(firstFunc, uintptr(i)*goarch.PtrSize)
8180 f := *(*func())(unsafe.Pointer(&p))
8181 f()
8182 }
8183
8184 if inittrace.active {
8185 end := nanotime()
8186
8187 after := inittrace
8188
8189 f := *(*func())(unsafe.Pointer(&firstFunc))
8190 pkg := funcpkgpath(findfunc(abi.FuncPCABIInternal(f)))
8191
8192 var sbuf [24]byte
8193 print("init ", pkg, " @")
8194 print(string(fmtNSAsMS(sbuf[:], uint64(start-runtimeInitTime))), " ms, ")
8195 print(string(fmtNSAsMS(sbuf[:], uint64(end-start))), " ms clock, ")
8196 print(string(itoa(sbuf[:], after.bytes-before.bytes)), " bytes, ")
8197 print(string(itoa(sbuf[:], after.allocs-before.allocs)), " allocs")
8198 print("\n")
8199 }
8200
8201 t.state = 2
8202 }
8203 }
8204
View as plain text