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