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