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