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
1674
1675 gp.m.p.ptr().status = _Pgcstop
1676 gp.m.p.ptr().gcStopTime = start
1677 sched.stopwait--
1678
1679
1680 for _, pp := range allp {
1681 if thread, ok := setBlockOnExitSyscall(pp); ok {
1682 thread.gcstopP()
1683 thread.resume()
1684 }
1685 }
1686
1687
1688 now := nanotime()
1689 for {
1690 pp, _ := pidleget(now)
1691 if pp == nil {
1692 break
1693 }
1694 pp.status = _Pgcstop
1695 pp.gcStopTime = nanotime()
1696 sched.stopwait--
1697 }
1698 wait := sched.stopwait > 0
1699 unlock(&sched.lock)
1700
1701
1702 if wait {
1703 preemptall()
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 if atomic.Load(&worldsema) != 0 {
2161
2162 throw("worldsema not held")
2163 }
2164
2165 mp := acquirem()
2166 pp := getg().m.p.ptr()
2167
2168 lock(&sched.lock)
2169 if sched.safePointWait != 0 {
2170 throw("forEachP: sched.safePointWait != 0")
2171 }
2172 sched.safePointWait = gomaxprocs - 1
2173 sched.safePointFn = fn
2174
2175
2176 for _, p2 := range allp {
2177 if p2 != pp {
2178 atomic.Store(&p2.runSafePointFn, 1)
2179 }
2180 }
2181
2182
2183
2184
2185
2186
2187
2188 for p := sched.pidle.ptr(); p != nil; p = p.link.ptr() {
2189 if atomic.Cas(&p.runSafePointFn, 1, 0) {
2190 fn(p)
2191 sched.safePointWait--
2192 }
2193 }
2194
2195 wait := sched.safePointWait > 0
2196 unlock(&sched.lock)
2197
2198 if wait {
2199 preemptall()
2200 }
2201
2202
2203 fn(pp)
2204
2205
2206
2207 for _, p2 := range allp {
2208 if atomic.Load(&p2.runSafePointFn) != 1 {
2209
2210 continue
2211 }
2212 if thread, ok := setBlockOnExitSyscall(p2); ok {
2213 thread.takeP()
2214 thread.resume()
2215 handoffp(p2)
2216 }
2217 }
2218
2219
2220 if wait {
2221 for {
2222
2223
2224
2225
2226 if notetsleep(&sched.safePointNote, 100*1000) {
2227 noteclear(&sched.safePointNote)
2228 break
2229 }
2230 preemptall()
2231 }
2232 }
2233 if sched.safePointWait != 0 {
2234 throw("forEachP: not done")
2235 }
2236 for _, p2 := range allp {
2237 if p2.runSafePointFn != 0 {
2238 throw("forEachP: P did not run fn")
2239 }
2240 }
2241
2242 lock(&sched.lock)
2243 sched.safePointFn = nil
2244 unlock(&sched.lock)
2245 releasem(mp)
2246 }
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259 func runSafePointFn() {
2260 p := getg().m.p.ptr()
2261
2262
2263
2264 if !atomic.Cas(&p.runSafePointFn, 1, 0) {
2265 return
2266 }
2267 sched.safePointFn(p)
2268 lock(&sched.lock)
2269 sched.safePointWait--
2270 if sched.safePointWait == 0 {
2271 notewakeup(&sched.safePointNote)
2272 }
2273 unlock(&sched.lock)
2274 }
2275
2276
2277
2278
2279 var cgoThreadStart unsafe.Pointer
2280
2281 type cgothreadstart struct {
2282 g guintptr
2283 tls *uint64
2284 fn unsafe.Pointer
2285 }
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296 func allocm(pp *p, fn func(), id int64) *m {
2297 allocmLock.rlock()
2298
2299
2300
2301
2302 acquirem()
2303
2304 gp := getg()
2305 if gp.m.p == 0 {
2306 acquirep(pp)
2307 }
2308
2309
2310
2311 if sched.freem != nil {
2312 lock(&sched.lock)
2313 var newList *m
2314 for freem := sched.freem; freem != nil; {
2315
2316 wait := freem.freeWait.Load()
2317 if wait == freeMWait {
2318 next := freem.freelink
2319 freem.freelink = newList
2320 newList = freem
2321 freem = next
2322 continue
2323 }
2324
2325
2326
2327 if traceEnabled() || traceShuttingDown() {
2328 traceThreadDestroy(freem)
2329 }
2330
2331
2332
2333 if wait == freeMStack {
2334
2335
2336
2337 systemstack(func() {
2338 stackfree(freem.g0.stack)
2339 if valgrindenabled {
2340 valgrindDeregisterStack(freem.g0.valgrindStackID)
2341 freem.g0.valgrindStackID = 0
2342 }
2343 })
2344 }
2345 freem = freem.freelink
2346 }
2347 sched.freem = newList
2348 unlock(&sched.lock)
2349 }
2350
2351 mp := &new(mPadded).m
2352 mp.mstartfn = fn
2353 mcommoninit(mp, id)
2354
2355
2356
2357 if iscgo || mStackIsSystemAllocated() {
2358 mp.g0 = malg(-1)
2359 } else {
2360 mp.g0 = malg(16384 * sys.StackGuardMultiplier)
2361 }
2362 mp.g0.m = mp
2363
2364 if pp == gp.m.p.ptr() {
2365 releasep()
2366 }
2367
2368 releasem(gp.m)
2369 allocmLock.runlock()
2370 return mp
2371 }
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412 func needm(signal bool) {
2413 if (iscgo || GOOS == "windows") && !cgoHasExtraM {
2414
2415
2416
2417
2418
2419
2420 writeErrStr("fatal error: cgo callback before cgo call\n")
2421 exit(1)
2422 }
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432 var sigmask sigset
2433 sigsave(&sigmask)
2434 sigblock(false)
2435
2436
2437
2438
2439 mp, last := getExtraM()
2440
2441
2442
2443
2444
2445
2446
2447
2448 mp.needextram = last
2449
2450
2451 mp.sigmask = sigmask
2452
2453
2454
2455 setg(mp.g0)
2456 sp := sys.GetCallerSP()
2457 callbackUpdateSystemStack(mp, sp, signal)
2458
2459
2460
2461
2462 mp.isExtraInC = false
2463
2464
2465 asminit()
2466 minit()
2467
2468
2469
2470
2471
2472
2473 var trace traceLocker
2474 if !signal {
2475 trace = traceAcquire()
2476 }
2477
2478
2479 casgstatus(mp.curg, _Gdeadextra, _Gsyscall)
2480 sched.ngsys.Add(-1)
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490 addGSyscallNoP(mp)
2491
2492 if !signal {
2493 if trace.ok() {
2494 trace.GoCreateSyscall(mp.curg)
2495 traceRelease(trace)
2496 }
2497 }
2498 mp.isExtraInSig = signal
2499 }
2500
2501
2502
2503
2504 func needAndBindM() {
2505 needm(false)
2506
2507 if _cgo_pthread_key_created != nil && *(*uintptr)(_cgo_pthread_key_created) != 0 {
2508 cgoBindM()
2509 }
2510 }
2511
2512
2513
2514
2515 func newextram() {
2516 c := extraMWaiters.Swap(0)
2517 if c > 0 {
2518 for i := uint32(0); i < c; i++ {
2519 oneNewExtraM()
2520 }
2521 } else if extraMLength.Load() == 0 {
2522
2523 oneNewExtraM()
2524 }
2525 }
2526
2527
2528 func oneNewExtraM() {
2529
2530
2531
2532
2533
2534 mp := allocm(nil, nil, -1)
2535 gp := malg(4096)
2536 gp.sched.pc = abi.FuncPCABI0(goexit) + sys.PCQuantum
2537 gp.sched.sp = gp.stack.hi
2538 gp.sched.sp -= 4 * goarch.PtrSize
2539 gp.sched.lr = 0
2540 gp.sched.g = guintptr(unsafe.Pointer(gp))
2541 gp.syscallpc = gp.sched.pc
2542 gp.syscallsp = gp.sched.sp
2543 gp.stktopsp = gp.sched.sp
2544
2545
2546
2547 casgstatus(gp, _Gidle, _Gdeadextra)
2548 gp.m = mp
2549 mp.curg = gp
2550 mp.isextra = true
2551
2552 mp.isExtraInC = true
2553 mp.lockedInt++
2554 mp.lockedg.set(gp)
2555 gp.lockedm.set(mp)
2556 gp.goid = sched.goidgen.Add(1)
2557 if raceenabled {
2558 gp.racectx = racegostart(abi.FuncPCABIInternal(newextram) + sys.PCQuantum)
2559 }
2560
2561 allgadd(gp)
2562
2563
2564
2565
2566
2567 sched.ngsys.Add(1)
2568
2569
2570 addExtraM(mp)
2571 }
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606 func dropm() {
2607
2608
2609
2610 mp := getg().m
2611
2612
2613
2614
2615
2616 var trace traceLocker
2617 if !mp.isExtraInSig {
2618 trace = traceAcquire()
2619 }
2620
2621
2622 casgstatus(mp.curg, _Gsyscall, _Gdeadextra)
2623 mp.curg.preemptStop = false
2624 sched.ngsys.Add(1)
2625 decGSyscallNoP(mp)
2626
2627 if !mp.isExtraInSig {
2628 if trace.ok() {
2629 trace.GoDestroySyscall()
2630 traceRelease(trace)
2631 }
2632 }
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647 mp.syscalltick--
2648
2649
2650
2651 mp.curg.trace.reset()
2652
2653
2654
2655
2656 if traceEnabled() || traceShuttingDown() {
2657
2658
2659
2660
2661
2662
2663
2664 lock(&sched.lock)
2665 traceThreadDestroy(mp)
2666 unlock(&sched.lock)
2667 }
2668 mp.isExtraInSig = false
2669
2670
2671
2672
2673
2674 sigmask := mp.sigmask
2675 sigblock(false)
2676 unminit()
2677
2678 setg(nil)
2679
2680
2681
2682 g0 := mp.g0
2683 g0.stack.hi = 0
2684 g0.stack.lo = 0
2685 g0.stackguard0 = 0
2686 g0.stackguard1 = 0
2687 mp.g0StackAccurate = false
2688
2689 putExtraM(mp)
2690
2691 msigrestore(sigmask)
2692 }
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714 func cgoBindM() {
2715 if GOOS == "windows" || GOOS == "plan9" {
2716 fatal("bindm in unexpected GOOS")
2717 }
2718 g := getg()
2719 if g.m.g0 != g {
2720 fatal("the current g is not g0")
2721 }
2722 if _cgo_bindm != nil {
2723 asmcgocall(_cgo_bindm, unsafe.Pointer(g))
2724 }
2725 }
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738 func getm() uintptr {
2739 return uintptr(unsafe.Pointer(getg().m))
2740 }
2741
2742 var (
2743
2744
2745
2746
2747
2748
2749 extraM atomic.Uintptr
2750
2751 extraMLength atomic.Uint32
2752
2753 extraMWaiters atomic.Uint32
2754
2755
2756 extraMInUse atomic.Uint32
2757 )
2758
2759
2760
2761
2762
2763
2764
2765
2766 func lockextra(nilokay bool) *m {
2767 const locked = 1
2768
2769 incr := false
2770 for {
2771 old := extraM.Load()
2772 if old == locked {
2773 osyield_no_g()
2774 continue
2775 }
2776 if old == 0 && !nilokay {
2777 if !incr {
2778
2779
2780
2781 extraMWaiters.Add(1)
2782 incr = true
2783 }
2784 usleep_no_g(1)
2785 continue
2786 }
2787 if extraM.CompareAndSwap(old, locked) {
2788 return (*m)(unsafe.Pointer(old))
2789 }
2790 osyield_no_g()
2791 continue
2792 }
2793 }
2794
2795
2796 func unlockextra(mp *m, delta int32) {
2797 extraMLength.Add(delta)
2798 extraM.Store(uintptr(unsafe.Pointer(mp)))
2799 }
2800
2801
2802
2803
2804
2805
2806
2807
2808 func getExtraM() (mp *m, last bool) {
2809 mp = lockextra(false)
2810 extraMInUse.Add(1)
2811 unlockextra(mp.schedlink.ptr(), -1)
2812 return mp, mp.schedlink.ptr() == nil
2813 }
2814
2815
2816
2817
2818
2819 func putExtraM(mp *m) {
2820 extraMInUse.Add(-1)
2821 addExtraM(mp)
2822 }
2823
2824
2825
2826
2827 func addExtraM(mp *m) {
2828 mnext := lockextra(true)
2829 mp.schedlink.set(mnext)
2830 unlockextra(mp, 1)
2831 }
2832
2833 var (
2834
2835
2836
2837 allocmLock rwmutex
2838
2839
2840
2841
2842 execLock rwmutex
2843 )
2844
2845
2846
2847 const (
2848 failthreadcreate = "runtime: failed to create new OS thread\n"
2849 failallocatestack = "runtime: failed to allocate stack for the new OS thread\n"
2850 )
2851
2852
2853
2854
2855 var newmHandoff struct {
2856 lock mutex
2857
2858
2859
2860 newm muintptr
2861
2862
2863
2864 waiting bool
2865 wake note
2866
2867
2868
2869
2870 haveTemplateThread uint32
2871 }
2872
2873
2874
2875
2876
2877
2878
2879
2880 func newm(fn func(), pp *p, id int64) {
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891 acquirem()
2892
2893 mp := allocm(pp, fn, id)
2894 mp.nextp.set(pp)
2895 mp.sigmask = initSigmask
2896 if gp := getg(); gp != nil && gp.m != nil && (gp.m.lockedExt != 0 || gp.m.incgo) && GOOS != "plan9" {
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908 lock(&newmHandoff.lock)
2909 if newmHandoff.haveTemplateThread == 0 {
2910 throw("on a locked thread with no template thread")
2911 }
2912 mp.schedlink = newmHandoff.newm
2913 newmHandoff.newm.set(mp)
2914 if newmHandoff.waiting {
2915 newmHandoff.waiting = false
2916 notewakeup(&newmHandoff.wake)
2917 }
2918 unlock(&newmHandoff.lock)
2919
2920
2921
2922 releasem(getg().m)
2923 return
2924 }
2925 newm1(mp)
2926 releasem(getg().m)
2927 }
2928
2929 func newm1(mp *m) {
2930 if iscgo && _cgo_thread_start != nil {
2931 var ts cgothreadstart
2932 ts.g.set(mp.g0)
2933 ts.tls = (*uint64)(unsafe.Pointer(&mp.tls[0]))
2934 ts.fn = unsafe.Pointer(abi.FuncPCABI0(mstart))
2935 if msanenabled {
2936 msanwrite(unsafe.Pointer(&ts), unsafe.Sizeof(ts))
2937 }
2938 if asanenabled {
2939 asanwrite(unsafe.Pointer(&ts), unsafe.Sizeof(ts))
2940 }
2941 execLock.rlock()
2942 asmcgocall(_cgo_thread_start, unsafe.Pointer(&ts))
2943 execLock.runlock()
2944 return
2945 }
2946 execLock.rlock()
2947 newosproc(mp)
2948 execLock.runlock()
2949 }
2950
2951
2952
2953
2954
2955 func startTemplateThread() {
2956 if GOARCH == "wasm" {
2957 return
2958 }
2959
2960
2961
2962 mp := acquirem()
2963 if !atomic.Cas(&newmHandoff.haveTemplateThread, 0, 1) {
2964 releasem(mp)
2965 return
2966 }
2967 newm(templateThread, nil, -1)
2968 releasem(mp)
2969 }
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983 func templateThread() {
2984 lock(&sched.lock)
2985 sched.nmsys++
2986 checkdead()
2987 unlock(&sched.lock)
2988
2989 for {
2990 lock(&newmHandoff.lock)
2991 for newmHandoff.newm != 0 {
2992 newm := newmHandoff.newm.ptr()
2993 newmHandoff.newm = 0
2994 unlock(&newmHandoff.lock)
2995 for newm != nil {
2996 next := newm.schedlink.ptr()
2997 newm.schedlink = 0
2998 newm1(newm)
2999 newm = next
3000 }
3001 lock(&newmHandoff.lock)
3002 }
3003 newmHandoff.waiting = true
3004 noteclear(&newmHandoff.wake)
3005 unlock(&newmHandoff.lock)
3006 notesleep(&newmHandoff.wake)
3007 }
3008 }
3009
3010
3011
3012 func stopm() {
3013 gp := getg()
3014
3015 if gp.m.locks != 0 {
3016 throw("stopm holding locks")
3017 }
3018 if gp.m.p != 0 {
3019 throw("stopm holding p")
3020 }
3021 if gp.m.spinning {
3022 throw("stopm spinning")
3023 }
3024
3025 lock(&sched.lock)
3026 mput(gp.m)
3027 unlock(&sched.lock)
3028 mPark()
3029 acquirep(gp.m.nextp.ptr())
3030 gp.m.nextp = 0
3031 }
3032
3033 func mspinning() {
3034
3035 getg().m.spinning = true
3036 }
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055 func startm(pp *p, spinning, lockheld bool) {
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072 mp := acquirem()
3073 if !lockheld {
3074 lock(&sched.lock)
3075 }
3076 if pp == nil {
3077 if spinning {
3078
3079
3080
3081 throw("startm: P required for spinning=true")
3082 }
3083 pp, _ = pidleget(0)
3084 if pp == nil {
3085 if !lockheld {
3086 unlock(&sched.lock)
3087 }
3088 releasem(mp)
3089 return
3090 }
3091 }
3092 nmp := mget()
3093 if nmp == nil {
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108 id := mReserveID()
3109 unlock(&sched.lock)
3110
3111 var fn func()
3112 if spinning {
3113
3114 fn = mspinning
3115 }
3116 newm(fn, pp, id)
3117
3118 if lockheld {
3119 lock(&sched.lock)
3120 }
3121
3122
3123 releasem(mp)
3124 return
3125 }
3126 if !lockheld {
3127 unlock(&sched.lock)
3128 }
3129 if nmp.spinning {
3130 throw("startm: m is spinning")
3131 }
3132 if nmp.nextp != 0 {
3133 throw("startm: m has p")
3134 }
3135 if spinning && !runqempty(pp) {
3136 throw("startm: p has runnable gs")
3137 }
3138
3139 nmp.spinning = spinning
3140 nmp.nextp.set(pp)
3141 notewakeup(&nmp.park)
3142
3143
3144 releasem(mp)
3145 }
3146
3147
3148
3149
3150
3151 func handoffp(pp *p) {
3152
3153
3154
3155
3156 if !runqempty(pp) || !sched.runq.empty() {
3157 startm(pp, false, false)
3158 return
3159 }
3160
3161 if (traceEnabled() || traceShuttingDown()) && traceReaderAvailable() != nil {
3162 startm(pp, false, false)
3163 return
3164 }
3165
3166 if gcBlackenEnabled != 0 && gcShouldScheduleWorker(pp) {
3167 startm(pp, false, false)
3168 return
3169 }
3170
3171
3172 if sched.nmspinning.Load()+sched.npidle.Load() == 0 && sched.nmspinning.CompareAndSwap(0, 1) {
3173 sched.needspinning.Store(0)
3174 startm(pp, true, false)
3175 return
3176 }
3177 lock(&sched.lock)
3178 if sched.gcwaiting.Load() {
3179 pp.status = _Pgcstop
3180 pp.gcStopTime = nanotime()
3181 sched.stopwait--
3182 if sched.stopwait == 0 {
3183 notewakeup(&sched.stopnote)
3184 }
3185 unlock(&sched.lock)
3186 return
3187 }
3188 if pp.runSafePointFn != 0 && atomic.Cas(&pp.runSafePointFn, 1, 0) {
3189 sched.safePointFn(pp)
3190 sched.safePointWait--
3191 if sched.safePointWait == 0 {
3192 notewakeup(&sched.safePointNote)
3193 }
3194 }
3195 if !sched.runq.empty() {
3196 unlock(&sched.lock)
3197 startm(pp, false, false)
3198 return
3199 }
3200
3201
3202 if sched.npidle.Load() == gomaxprocs-1 && sched.lastpoll.Load() != 0 {
3203 unlock(&sched.lock)
3204 startm(pp, false, false)
3205 return
3206 }
3207
3208
3209
3210 when := pp.timers.wakeTime()
3211 pidleput(pp, 0)
3212 unlock(&sched.lock)
3213
3214 if when != 0 {
3215 wakeNetPoller(when)
3216 }
3217 }
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232 func wakep() {
3233
3234
3235 if sched.nmspinning.Load() != 0 || !sched.nmspinning.CompareAndSwap(0, 1) {
3236 return
3237 }
3238
3239
3240
3241
3242
3243
3244 mp := acquirem()
3245
3246 var pp *p
3247 lock(&sched.lock)
3248 pp, _ = pidlegetSpinning(0)
3249 if pp == nil {
3250 if sched.nmspinning.Add(-1) < 0 {
3251 throw("wakep: negative nmspinning")
3252 }
3253 unlock(&sched.lock)
3254 releasem(mp)
3255 return
3256 }
3257
3258
3259
3260
3261 unlock(&sched.lock)
3262
3263 startm(pp, true, false)
3264
3265 releasem(mp)
3266 }
3267
3268
3269
3270 func stoplockedm() {
3271 gp := getg()
3272
3273 if gp.m.lockedg == 0 || gp.m.lockedg.ptr().lockedm.ptr() != gp.m {
3274 throw("stoplockedm: inconsistent locking")
3275 }
3276 if gp.m.p != 0 {
3277
3278 pp := releasep()
3279 handoffp(pp)
3280 }
3281 incidlelocked(1)
3282
3283 mPark()
3284 status := readgstatus(gp.m.lockedg.ptr())
3285 if status&^_Gscan != _Grunnable {
3286 print("runtime:stoplockedm: lockedg (atomicstatus=", status, ") is not Grunnable or Gscanrunnable\n")
3287 dumpgstatus(gp.m.lockedg.ptr())
3288 throw("stoplockedm: not runnable")
3289 }
3290 acquirep(gp.m.nextp.ptr())
3291 gp.m.nextp = 0
3292 }
3293
3294
3295
3296
3297
3298 func startlockedm(gp *g) {
3299 mp := gp.lockedm.ptr()
3300 if mp == getg().m {
3301 throw("startlockedm: locked to me")
3302 }
3303 if mp.nextp != 0 {
3304 throw("startlockedm: m has p")
3305 }
3306
3307 incidlelocked(-1)
3308 pp := releasep()
3309 mp.nextp.set(pp)
3310 notewakeup(&mp.park)
3311 stopm()
3312 }
3313
3314
3315
3316 func gcstopm() {
3317 gp := getg()
3318
3319 if !sched.gcwaiting.Load() {
3320 throw("gcstopm: not waiting for gc")
3321 }
3322 if gp.m.spinning {
3323 gp.m.spinning = false
3324
3325
3326 if sched.nmspinning.Add(-1) < 0 {
3327 throw("gcstopm: negative nmspinning")
3328 }
3329 }
3330 pp := releasep()
3331 lock(&sched.lock)
3332 pp.status = _Pgcstop
3333 pp.gcStopTime = nanotime()
3334 sched.stopwait--
3335 if sched.stopwait == 0 {
3336 notewakeup(&sched.stopnote)
3337 }
3338 unlock(&sched.lock)
3339 stopm()
3340 }
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351 func execute(gp *g, inheritTime bool) {
3352 mp := getg().m
3353
3354 if goroutineProfile.active {
3355
3356
3357
3358 tryRecordGoroutineProfile(gp, nil, osyield)
3359 }
3360
3361
3362 mp.curg = gp
3363 gp.m = mp
3364 gp.syncSafePoint = false
3365 casgstatus(gp, _Grunnable, _Grunning)
3366 gp.waitsince = 0
3367 gp.preempt = false
3368 gp.stackguard0 = gp.stack.lo + stackGuard
3369 if !inheritTime {
3370 mp.p.ptr().schedtick++
3371 }
3372
3373 if sys.DITSupported && debug.dataindependenttiming != 1 {
3374 if gp.ditWanted && !mp.ditEnabled {
3375
3376
3377 sys.EnableDIT()
3378 mp.ditEnabled = true
3379 } else if !gp.ditWanted && mp.ditEnabled {
3380
3381
3382
3383
3384
3385 sys.DisableDIT()
3386 mp.ditEnabled = false
3387 }
3388 }
3389
3390
3391 hz := sched.profilehz
3392 if mp.profilehz != hz {
3393 setThreadCPUProfiler(hz)
3394 }
3395
3396 trace := traceAcquire()
3397 if trace.ok() {
3398 trace.GoStart()
3399 traceRelease(trace)
3400 }
3401
3402 gogo(&gp.sched)
3403 }
3404
3405
3406
3407
3408
3409 func findRunnable() (gp *g, inheritTime, tryWakeP bool) {
3410 mp := getg().m
3411
3412
3413
3414
3415
3416 top:
3417
3418
3419
3420 mp.clearAllpSnapshot()
3421
3422 pp := mp.p.ptr()
3423 if sched.gcwaiting.Load() {
3424 gcstopm()
3425 goto top
3426 }
3427 if pp.runSafePointFn != 0 {
3428 runSafePointFn()
3429 }
3430
3431
3432
3433
3434
3435 now, pollUntil, _ := pp.timers.check(0, nil)
3436
3437
3438 if traceEnabled() || traceShuttingDown() {
3439 gp := traceReader()
3440 if gp != nil {
3441 trace := traceAcquire()
3442 casgstatus(gp, _Gwaiting, _Grunnable)
3443 if trace.ok() {
3444 trace.GoUnpark(gp, 0)
3445 traceRelease(trace)
3446 }
3447 return gp, false, true
3448 }
3449 }
3450
3451
3452 if gcBlackenEnabled != 0 {
3453 gp, tnow := gcController.findRunnableGCWorker(pp, now)
3454 if gp != nil {
3455 return gp, false, true
3456 }
3457 now = tnow
3458 }
3459
3460
3461
3462
3463 if pp.schedtick%61 == 0 && !sched.runq.empty() {
3464 lock(&sched.lock)
3465 gp := globrunqget()
3466 unlock(&sched.lock)
3467 if gp != nil {
3468 return gp, false, false
3469 }
3470 }
3471
3472
3473 if fingStatus.Load()&(fingWait|fingWake) == fingWait|fingWake {
3474 if gp := wakefing(); gp != nil {
3475 ready(gp, 0, true)
3476 }
3477 }
3478
3479
3480 if gcCleanups.needsWake() {
3481 gcCleanups.wake()
3482 }
3483
3484 if *cgo_yield != nil {
3485 asmcgocall(*cgo_yield, nil)
3486 }
3487
3488
3489 if gp, inheritTime := runqget(pp); gp != nil {
3490 return gp, inheritTime, false
3491 }
3492
3493
3494 if !sched.runq.empty() {
3495 lock(&sched.lock)
3496 gp, q := globrunqgetbatch(int32(len(pp.runq)) / 2)
3497 unlock(&sched.lock)
3498 if gp != nil {
3499 if runqputbatch(pp, &q); !q.empty() {
3500 throw("Couldn't put Gs into empty local runq")
3501 }
3502 return gp, false, false
3503 }
3504 }
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515 if netpollinited() && netpollAnyWaiters() && sched.lastpoll.Load() != 0 && sched.pollingNet.Swap(1) == 0 {
3516 list, delta := netpoll(0)
3517 sched.pollingNet.Store(0)
3518 if !list.empty() {
3519 gp := list.pop()
3520 injectglist(&list)
3521 netpollAdjustWaiters(delta)
3522 trace := traceAcquire()
3523 casgstatus(gp, _Gwaiting, _Grunnable)
3524 if trace.ok() {
3525 trace.GoUnpark(gp, 0)
3526 traceRelease(trace)
3527 }
3528 return gp, false, false
3529 }
3530 }
3531
3532
3533
3534
3535
3536
3537 if mp.spinning || 2*sched.nmspinning.Load() < gomaxprocs-sched.npidle.Load() {
3538 if !mp.spinning {
3539 mp.becomeSpinning()
3540 }
3541
3542 gp, inheritTime, tnow, w, newWork := stealWork(now)
3543 if gp != nil {
3544
3545 return gp, inheritTime, false
3546 }
3547 if newWork {
3548
3549
3550 goto top
3551 }
3552
3553 now = tnow
3554 if w != 0 && (pollUntil == 0 || w < pollUntil) {
3555
3556 pollUntil = w
3557 }
3558 }
3559
3560
3561
3562
3563
3564 if gcBlackenEnabled != 0 && gcShouldScheduleWorker(pp) && gcController.addIdleMarkWorker() {
3565 node := (*gcBgMarkWorkerNode)(gcBgMarkWorkerPool.pop())
3566 if node != nil {
3567 pp.gcMarkWorkerMode = gcMarkWorkerIdleMode
3568 gp := node.gp.ptr()
3569
3570 trace := traceAcquire()
3571 casgstatus(gp, _Gwaiting, _Grunnable)
3572 if trace.ok() {
3573 trace.GoUnpark(gp, 0)
3574 traceRelease(trace)
3575 }
3576 return gp, false, false
3577 }
3578 gcController.removeIdleMarkWorker()
3579 }
3580
3581
3582
3583
3584
3585 gp, otherReady := beforeIdle(now, pollUntil)
3586 if gp != nil {
3587 trace := traceAcquire()
3588 casgstatus(gp, _Gwaiting, _Grunnable)
3589 if trace.ok() {
3590 trace.GoUnpark(gp, 0)
3591 traceRelease(trace)
3592 }
3593 return gp, false, false
3594 }
3595 if otherReady {
3596 goto top
3597 }
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607 allpSnapshot := mp.snapshotAllp()
3608
3609
3610 idlepMaskSnapshot := idlepMask
3611 timerpMaskSnapshot := timerpMask
3612
3613
3614 lock(&sched.lock)
3615 if sched.gcwaiting.Load() || pp.runSafePointFn != 0 {
3616 unlock(&sched.lock)
3617 goto top
3618 }
3619 if !sched.runq.empty() {
3620 gp, q := globrunqgetbatch(int32(len(pp.runq)) / 2)
3621 unlock(&sched.lock)
3622 if gp == nil {
3623 throw("global runq empty with non-zero runqsize")
3624 }
3625 if runqputbatch(pp, &q); !q.empty() {
3626 throw("Couldn't put Gs into empty local runq")
3627 }
3628 return gp, false, false
3629 }
3630 if !mp.spinning && sched.needspinning.Load() == 1 {
3631
3632 mp.becomeSpinning()
3633 unlock(&sched.lock)
3634 goto top
3635 }
3636 if releasep() != pp {
3637 throw("findRunnable: wrong p")
3638 }
3639 now = pidleput(pp, now)
3640 unlock(&sched.lock)
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678 wasSpinning := mp.spinning
3679 if mp.spinning {
3680 mp.spinning = false
3681 if sched.nmspinning.Add(-1) < 0 {
3682 throw("findRunnable: negative nmspinning")
3683 }
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696 lock(&sched.lock)
3697 if !sched.runq.empty() {
3698 pp, _ := pidlegetSpinning(0)
3699 if pp != nil {
3700 gp, q := globrunqgetbatch(int32(len(pp.runq)) / 2)
3701 unlock(&sched.lock)
3702 if gp == nil {
3703 throw("global runq empty with non-zero runqsize")
3704 }
3705 if runqputbatch(pp, &q); !q.empty() {
3706 throw("Couldn't put Gs into empty local runq")
3707 }
3708 acquirep(pp)
3709 mp.becomeSpinning()
3710 return gp, false, false
3711 }
3712 }
3713 unlock(&sched.lock)
3714
3715 pp := checkRunqsNoP(allpSnapshot, idlepMaskSnapshot)
3716 if pp != nil {
3717 acquirep(pp)
3718 mp.becomeSpinning()
3719 goto top
3720 }
3721
3722
3723 pp, gp := checkIdleGCNoP()
3724 if pp != nil {
3725 acquirep(pp)
3726 mp.becomeSpinning()
3727
3728
3729 pp.gcMarkWorkerMode = gcMarkWorkerIdleMode
3730 trace := traceAcquire()
3731 casgstatus(gp, _Gwaiting, _Grunnable)
3732 if trace.ok() {
3733 trace.GoUnpark(gp, 0)
3734 traceRelease(trace)
3735 }
3736 return gp, false, false
3737 }
3738
3739
3740
3741
3742
3743
3744
3745 pollUntil = checkTimersNoP(allpSnapshot, timerpMaskSnapshot, pollUntil)
3746 }
3747
3748
3749
3750
3751
3752 if netpollinited() && (netpollAnyWaiters() || pollUntil != 0) && sched.lastpoll.Swap(0) != 0 {
3753 sched.pollUntil.Store(pollUntil)
3754 if mp.p != 0 {
3755 throw("findRunnable: netpoll with p")
3756 }
3757 if mp.spinning {
3758 throw("findRunnable: netpoll with spinning")
3759 }
3760 delay := int64(-1)
3761 if pollUntil != 0 {
3762 if now == 0 {
3763 now = nanotime()
3764 }
3765 delay = pollUntil - now
3766 if delay < 0 {
3767 delay = 0
3768 }
3769 }
3770 if faketime != 0 {
3771
3772 delay = 0
3773 }
3774 list, delta := netpoll(delay)
3775
3776 now = nanotime()
3777 sched.pollUntil.Store(0)
3778 sched.lastpoll.Store(now)
3779 if faketime != 0 && list.empty() {
3780
3781
3782 stopm()
3783 goto top
3784 }
3785 lock(&sched.lock)
3786 pp, _ := pidleget(now)
3787 unlock(&sched.lock)
3788 if pp == nil {
3789 injectglist(&list)
3790 netpollAdjustWaiters(delta)
3791 } else {
3792 acquirep(pp)
3793 if !list.empty() {
3794 gp := list.pop()
3795 injectglist(&list)
3796 netpollAdjustWaiters(delta)
3797 trace := traceAcquire()
3798 casgstatus(gp, _Gwaiting, _Grunnable)
3799 if trace.ok() {
3800 trace.GoUnpark(gp, 0)
3801 traceRelease(trace)
3802 }
3803 return gp, false, false
3804 }
3805 if wasSpinning {
3806 mp.becomeSpinning()
3807 }
3808 goto top
3809 }
3810 } else if pollUntil != 0 && netpollinited() {
3811 pollerPollUntil := sched.pollUntil.Load()
3812 if pollerPollUntil == 0 || pollerPollUntil > pollUntil {
3813 netpollBreak()
3814 }
3815 }
3816 stopm()
3817 goto top
3818 }
3819
3820
3821
3822
3823
3824 func pollWork() bool {
3825 if !sched.runq.empty() {
3826 return true
3827 }
3828 p := getg().m.p.ptr()
3829 if !runqempty(p) {
3830 return true
3831 }
3832 if netpollinited() && netpollAnyWaiters() && sched.lastpoll.Load() != 0 {
3833 if list, delta := netpoll(0); !list.empty() {
3834 injectglist(&list)
3835 netpollAdjustWaiters(delta)
3836 return true
3837 }
3838 }
3839 return false
3840 }
3841
3842
3843
3844
3845
3846
3847
3848 func stealWork(now int64) (gp *g, inheritTime bool, rnow, pollUntil int64, newWork bool) {
3849 pp := getg().m.p.ptr()
3850
3851 ranTimer := false
3852
3853 const stealTries = 4
3854 for i := 0; i < stealTries; i++ {
3855 stealTimersOrRunNextG := i == stealTries-1
3856
3857 for enum := stealOrder.start(cheaprand()); !enum.done(); enum.next() {
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 if sched.gcwaiting.Load() {
3906
3907
3908 return nil, false, now, pollUntil, true
3909 }
3910 }
3911 }
3912
3913
3914
3915
3916 return nil, false, now, pollUntil, ranTimer
3917 }
3918
3919
3920
3921
3922
3923
3924 func checkRunqsNoP(allpSnapshot []*p, idlepMaskSnapshot pMask) *p {
3925 for id, p2 := range allpSnapshot {
3926 if !idlepMaskSnapshot.read(uint32(id)) && !runqempty(p2) {
3927 lock(&sched.lock)
3928 pp, _ := pidlegetSpinning(0)
3929 if pp == nil {
3930
3931 unlock(&sched.lock)
3932 return nil
3933 }
3934 unlock(&sched.lock)
3935 return pp
3936 }
3937 }
3938
3939
3940 return nil
3941 }
3942
3943
3944
3945
3946 func checkTimersNoP(allpSnapshot []*p, timerpMaskSnapshot pMask, pollUntil int64) int64 {
3947 for id, p2 := range allpSnapshot {
3948 if timerpMaskSnapshot.read(uint32(id)) {
3949 w := p2.timers.wakeTime()
3950 if w != 0 && (pollUntil == 0 || w < pollUntil) {
3951 pollUntil = w
3952 }
3953 }
3954 }
3955
3956 return pollUntil
3957 }
3958
3959
3960
3961
3962
3963 func checkIdleGCNoP() (*p, *g) {
3964
3965
3966
3967
3968
3969
3970 if atomic.Load(&gcBlackenEnabled) == 0 || !gcController.needIdleMarkWorker() {
3971 return nil, nil
3972 }
3973 if !gcShouldScheduleWorker(nil) {
3974 return nil, nil
3975 }
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994 lock(&sched.lock)
3995 pp, now := pidlegetSpinning(0)
3996 if pp == nil {
3997 unlock(&sched.lock)
3998 return nil, nil
3999 }
4000
4001
4002 if gcBlackenEnabled == 0 || !gcController.addIdleMarkWorker() {
4003 pidleput(pp, now)
4004 unlock(&sched.lock)
4005 return nil, nil
4006 }
4007
4008 node := (*gcBgMarkWorkerNode)(gcBgMarkWorkerPool.pop())
4009 if node == nil {
4010 pidleput(pp, now)
4011 unlock(&sched.lock)
4012 gcController.removeIdleMarkWorker()
4013 return nil, nil
4014 }
4015
4016 unlock(&sched.lock)
4017
4018 return pp, node.gp.ptr()
4019 }
4020
4021
4022
4023
4024 func wakeNetPoller(when int64) {
4025 if sched.lastpoll.Load() == 0 {
4026
4027
4028
4029
4030 pollerPollUntil := sched.pollUntil.Load()
4031 if pollerPollUntil == 0 || pollerPollUntil > when {
4032 netpollBreak()
4033 }
4034 } else {
4035
4036
4037 if GOOS != "plan9" {
4038 wakep()
4039 }
4040 }
4041 }
4042
4043 func resetspinning() {
4044 gp := getg()
4045 if !gp.m.spinning {
4046 throw("resetspinning: not a spinning m")
4047 }
4048 gp.m.spinning = false
4049 nmspinning := sched.nmspinning.Add(-1)
4050 if nmspinning < 0 {
4051 throw("findRunnable: negative nmspinning")
4052 }
4053
4054
4055
4056 wakep()
4057 }
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067 func injectglist(glist *gList) {
4068 if glist.empty() {
4069 return
4070 }
4071
4072
4073
4074 var tail *g
4075 trace := traceAcquire()
4076 for gp := glist.head.ptr(); gp != nil; gp = gp.schedlink.ptr() {
4077 tail = gp
4078 casgstatus(gp, _Gwaiting, _Grunnable)
4079 if trace.ok() {
4080 trace.GoUnpark(gp, 0)
4081 }
4082 }
4083 if trace.ok() {
4084 traceRelease(trace)
4085 }
4086
4087
4088 q := gQueue{glist.head, tail.guintptr(), glist.size}
4089 *glist = gList{}
4090
4091 startIdle := func(n int32) {
4092 for ; n > 0; n-- {
4093 mp := acquirem()
4094 lock(&sched.lock)
4095
4096 pp, _ := pidlegetSpinning(0)
4097 if pp == nil {
4098 unlock(&sched.lock)
4099 releasem(mp)
4100 break
4101 }
4102
4103 startm(pp, false, true)
4104 unlock(&sched.lock)
4105 releasem(mp)
4106 }
4107 }
4108
4109 pp := getg().m.p.ptr()
4110 if pp == nil {
4111 n := q.size
4112 lock(&sched.lock)
4113 globrunqputbatch(&q)
4114 unlock(&sched.lock)
4115 startIdle(n)
4116 return
4117 }
4118
4119 var globq gQueue
4120 npidle := sched.npidle.Load()
4121 for ; npidle > 0 && !q.empty(); npidle-- {
4122 g := q.pop()
4123 globq.pushBack(g)
4124 }
4125 if !globq.empty() {
4126 n := globq.size
4127 lock(&sched.lock)
4128 globrunqputbatch(&globq)
4129 unlock(&sched.lock)
4130 startIdle(n)
4131 }
4132
4133 if runqputbatch(pp, &q); !q.empty() {
4134 lock(&sched.lock)
4135 globrunqputbatch(&q)
4136 unlock(&sched.lock)
4137 }
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152 wakep()
4153 }
4154
4155
4156
4157 func schedule() {
4158 mp := getg().m
4159
4160 if mp.locks != 0 {
4161 throw("schedule: holding locks")
4162 }
4163
4164 if mp.lockedg != 0 {
4165 stoplockedm()
4166 execute(mp.lockedg.ptr(), false)
4167 }
4168
4169
4170
4171 if mp.incgo {
4172 throw("schedule: in cgo")
4173 }
4174
4175 top:
4176 pp := mp.p.ptr()
4177 pp.preempt = false
4178
4179
4180
4181
4182 if mp.spinning && (pp.runnext != 0 || pp.runqhead != pp.runqtail) {
4183 throw("schedule: spinning with local work")
4184 }
4185
4186 gp, inheritTime, tryWakeP := findRunnable()
4187
4188
4189 pp = mp.p.ptr()
4190
4191
4192
4193
4194 mp.clearAllpSnapshot()
4195
4196
4197
4198
4199
4200
4201
4202
4203 gcController.releaseNextGCMarkWorker(pp)
4204
4205 if debug.dontfreezetheworld > 0 && freezing.Load() {
4206
4207
4208
4209
4210
4211
4212
4213 lock(&deadlock)
4214 lock(&deadlock)
4215 }
4216
4217
4218
4219
4220 if mp.spinning {
4221 resetspinning()
4222 }
4223
4224 if sched.disable.user && !schedEnabled(gp) {
4225
4226
4227
4228 lock(&sched.lock)
4229 if schedEnabled(gp) {
4230
4231
4232 unlock(&sched.lock)
4233 } else {
4234 sched.disable.runnable.pushBack(gp)
4235 unlock(&sched.lock)
4236 goto top
4237 }
4238 }
4239
4240
4241
4242 if tryWakeP {
4243 wakep()
4244 }
4245 if gp.lockedm != 0 {
4246
4247
4248 startlockedm(gp)
4249 goto top
4250 }
4251
4252 execute(gp, inheritTime)
4253 }
4254
4255
4256
4257
4258
4259
4260
4261
4262 func dropg() {
4263 gp := getg()
4264
4265 setMNoWB(&gp.m.curg.m, nil)
4266 setGNoWB(&gp.m.curg, nil)
4267 }
4268
4269 func parkunlock_c(gp *g, lock unsafe.Pointer) bool {
4270 unlock((*mutex)(lock))
4271 return true
4272 }
4273
4274
4275 func park_m(gp *g) {
4276 mp := getg().m
4277
4278 trace := traceAcquire()
4279
4280
4281
4282
4283
4284 bubble := gp.bubble
4285 if bubble != nil {
4286 bubble.incActive()
4287 }
4288
4289 if trace.ok() {
4290
4291
4292
4293 trace.GoPark(mp.waitTraceBlockReason, mp.waitTraceSkip)
4294 }
4295
4296
4297 casgstatus(gp, _Grunning, _Gwaiting)
4298 if trace.ok() {
4299 traceRelease(trace)
4300 }
4301
4302 dropg()
4303
4304 if fn := mp.waitunlockf; fn != nil {
4305 ok := fn(gp, mp.waitlock)
4306 mp.waitunlockf = nil
4307 mp.waitlock = nil
4308 if !ok {
4309 trace := traceAcquire()
4310 casgstatus(gp, _Gwaiting, _Grunnable)
4311 if bubble != nil {
4312 bubble.decActive()
4313 }
4314 if trace.ok() {
4315 trace.GoUnpark(gp, 2)
4316 traceRelease(trace)
4317 }
4318 execute(gp, true)
4319 }
4320 }
4321
4322 if bubble != nil {
4323 bubble.decActive()
4324 }
4325
4326 schedule()
4327 }
4328
4329 func goschedImpl(gp *g, preempted bool) {
4330 pp := gp.m.p.ptr()
4331 trace := traceAcquire()
4332 status := readgstatus(gp)
4333 if status&^_Gscan != _Grunning {
4334 dumpgstatus(gp)
4335 throw("bad g status")
4336 }
4337 if trace.ok() {
4338
4339
4340
4341 if preempted {
4342 trace.GoPreempt()
4343 } else {
4344 trace.GoSched()
4345 }
4346 }
4347 casgstatus(gp, _Grunning, _Grunnable)
4348 if trace.ok() {
4349 traceRelease(trace)
4350 }
4351
4352 dropg()
4353 if preempted && sched.gcwaiting.Load() {
4354
4355
4356 runqput(pp, gp, true)
4357 } else {
4358 lock(&sched.lock)
4359 globrunqput(gp)
4360 unlock(&sched.lock)
4361 }
4362
4363 if mainStarted {
4364 wakep()
4365 }
4366
4367 schedule()
4368 }
4369
4370
4371 func gosched_m(gp *g) {
4372 goschedImpl(gp, false)
4373 }
4374
4375
4376 func goschedguarded_m(gp *g) {
4377 if !canPreemptM(gp.m) {
4378 gogo(&gp.sched)
4379 }
4380 goschedImpl(gp, false)
4381 }
4382
4383 func gopreempt_m(gp *g) {
4384 goschedImpl(gp, true)
4385 }
4386
4387
4388
4389
4390 func preemptPark(gp *g) {
4391 status := readgstatus(gp)
4392 if status&^_Gscan != _Grunning {
4393 dumpgstatus(gp)
4394 throw("bad g status")
4395 }
4396
4397 if gp.asyncSafePoint {
4398
4399
4400
4401 f := findfunc(gp.sched.pc)
4402 if !f.valid() {
4403 throw("preempt at unknown pc")
4404 }
4405 if f.flag&abi.FuncFlagSPWrite != 0 {
4406 println("runtime: unexpected SPWRITE function", funcname(f), "in async preempt")
4407 throw("preempt SPWRITE")
4408 }
4409 }
4410
4411
4412
4413
4414
4415
4416
4417 casGToPreemptScan(gp, _Grunning, _Gscan|_Gpreempted)
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439 trace := traceAcquire()
4440 if trace.ok() {
4441 trace.GoPark(traceBlockPreempted, 0)
4442 }
4443
4444
4445
4446
4447 dropg()
4448
4449
4450 casfrom_Gscanstatus(gp, _Gscan|_Gpreempted, _Gpreempted)
4451 if trace.ok() {
4452 traceRelease(trace)
4453 }
4454
4455
4456 schedule()
4457 }
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473 func goyield() {
4474 checkTimeouts()
4475 mcall(goyield_m)
4476 }
4477
4478 func goyield_m(gp *g) {
4479 trace := traceAcquire()
4480 pp := gp.m.p.ptr()
4481 if trace.ok() {
4482
4483
4484
4485 trace.GoPreempt()
4486 }
4487 casgstatus(gp, _Grunning, _Grunnable)
4488 if trace.ok() {
4489 traceRelease(trace)
4490 }
4491 dropg()
4492 runqput(pp, gp, false)
4493 schedule()
4494 }
4495
4496
4497 func goexit1() {
4498 if raceenabled {
4499 if gp := getg(); gp.bubble != nil {
4500 racereleasemergeg(gp, gp.bubble.raceaddr())
4501 }
4502 racegoend()
4503 }
4504 trace := traceAcquire()
4505 if trace.ok() {
4506 trace.GoEnd()
4507 traceRelease(trace)
4508 }
4509 mcall(goexit0)
4510 }
4511
4512
4513 func goexit0(gp *g) {
4514 if goexperiment.RuntimeSecret && gp.secret > 0 {
4515
4516
4517 memclrNoHeapPointers(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo)
4518
4519
4520 }
4521 gdestroy(gp)
4522 schedule()
4523 }
4524
4525 func gdestroy(gp *g) {
4526 mp := getg().m
4527 pp := mp.p.ptr()
4528
4529 casgstatus(gp, _Grunning, _Gdead)
4530 gcController.addScannableStack(pp, -int64(gp.stack.hi-gp.stack.lo))
4531 if isSystemGoroutine(gp, false) {
4532 sched.ngsys.Add(-1)
4533 }
4534 gp.m = nil
4535 locked := gp.lockedm != 0
4536 gp.lockedm = 0
4537 mp.lockedg = 0
4538 gp.preemptStop = false
4539 gp.paniconfault = false
4540 gp._defer = nil
4541 gp._panic = nil
4542 gp.writebuf = nil
4543 gp.waitreason = waitReasonZero
4544 gp.param = nil
4545 gp.labels = nil
4546 gp.timer = nil
4547 gp.bubble = nil
4548 gp.fipsOnlyBypass = false
4549 gp.secret = 0
4550
4551 if gcBlackenEnabled != 0 && gp.gcAssistBytes > 0 {
4552
4553
4554
4555 assistWorkPerByte := gcController.assistWorkPerByte.Load()
4556 scanCredit := int64(assistWorkPerByte * float64(gp.gcAssistBytes))
4557 gcController.bgScanCredit.Add(scanCredit)
4558 gp.gcAssistBytes = 0
4559 }
4560
4561 dropg()
4562
4563 if GOARCH == "wasm" {
4564 gfput(pp, gp)
4565 return
4566 }
4567
4568 if locked && mp.lockedInt != 0 {
4569 print("runtime: mp.lockedInt = ", mp.lockedInt, "\n")
4570 if mp.isextra {
4571 throw("runtime.Goexit called in a thread that was not created by the Go runtime")
4572 }
4573 throw("exited a goroutine internally locked to the OS thread")
4574 }
4575 gfput(pp, gp)
4576 if locked {
4577
4578
4579
4580
4581
4582
4583 if GOOS != "plan9" {
4584 gogo(&mp.g0.sched)
4585 } else {
4586
4587
4588 mp.lockedExt = 0
4589 }
4590 }
4591 }
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601 func save(pc, sp, bp uintptr) {
4602 gp := getg()
4603
4604 if gp == gp.m.g0 || gp == gp.m.gsignal {
4605
4606
4607
4608
4609
4610 throw("save on system g not allowed")
4611 }
4612
4613 gp.sched.pc = pc
4614 gp.sched.sp = sp
4615 gp.sched.lr = 0
4616 gp.sched.bp = bp
4617
4618
4619
4620 if gp.sched.ctxt != nil {
4621 badctxt()
4622 }
4623 }
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649 func reentersyscall(pc, sp, bp uintptr) {
4650 gp := getg()
4651
4652
4653
4654 gp.m.locks++
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676 if goexperiment.RuntimeSecret {
4677 eraseSecretsSignalStk()
4678 }
4679
4680
4681
4682
4683
4684 gp.stackguard0 = stackPreempt
4685 gp.throwsplit = true
4686
4687
4688 gp.m.syscalltick = gp.m.p.ptr().syscalltick
4689
4690 pp := gp.m.p.ptr()
4691 if pp.runSafePointFn != 0 {
4692
4693 systemstack(runSafePointFn)
4694 }
4695 gp.m.oldp.set(pp)
4696
4697
4698 save(pc, sp, bp)
4699 gp.syscallsp = sp
4700 gp.syscallpc = pc
4701 gp.syscallbp = bp
4702
4703
4704 if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp {
4705 systemstack(func() {
4706 print("entersyscall inconsistent sp ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
4707 throw("entersyscall")
4708 })
4709 }
4710 if gp.syscallbp != 0 && gp.syscallbp < gp.stack.lo || gp.stack.hi < gp.syscallbp {
4711 systemstack(func() {
4712 print("entersyscall inconsistent bp ", hex(gp.syscallbp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
4713 throw("entersyscall")
4714 })
4715 }
4716 trace := traceAcquire()
4717 if trace.ok() {
4718
4719
4720
4721
4722 systemstack(func() {
4723 trace.GoSysCall()
4724 })
4725
4726 save(pc, sp, bp)
4727 }
4728 if sched.gcwaiting.Load() {
4729
4730
4731
4732 systemstack(func() {
4733 entersyscallHandleGCWait(trace)
4734 })
4735
4736 save(pc, sp, bp)
4737 }
4738
4739
4740
4741
4742
4743 if gp.bubble != nil || !gp.atomicstatus.CompareAndSwap(_Grunning, _Gsyscall) {
4744 casgstatus(gp, _Grunning, _Gsyscall)
4745 }
4746 if staticLockRanking {
4747
4748 save(pc, sp, bp)
4749 }
4750 if trace.ok() {
4751
4752
4753
4754 traceRelease(trace)
4755 }
4756 if sched.sysmonwait.Load() {
4757 systemstack(entersyscallWakeSysmon)
4758
4759 save(pc, sp, bp)
4760 }
4761 gp.m.locks--
4762 }
4763
4764
4765
4766
4767 const debugExtendGrunningNoP = false
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783 func entersyscall() {
4784
4785
4786
4787
4788 fp := getcallerfp()
4789 reentersyscall(sys.GetCallerPC(), sys.GetCallerSP(), fp)
4790 }
4791
4792 func entersyscallWakeSysmon() {
4793 lock(&sched.lock)
4794 if sched.sysmonwait.Load() {
4795 sched.sysmonwait.Store(false)
4796 notewakeup(&sched.sysmonnote)
4797 }
4798 unlock(&sched.lock)
4799 }
4800
4801 func entersyscallHandleGCWait(trace traceLocker) {
4802 gp := getg()
4803
4804 lock(&sched.lock)
4805 if sched.stopwait > 0 {
4806
4807 pp := gp.m.p.ptr()
4808 pp.m = 0
4809 gp.m.p = 0
4810 atomic.Store(&pp.status, _Pgcstop)
4811
4812 if trace.ok() {
4813 trace.ProcStop(pp)
4814 }
4815 addGSyscallNoP(gp.m)
4816 pp.gcStopTime = nanotime()
4817 pp.syscalltick++
4818 if sched.stopwait--; sched.stopwait == 0 {
4819 notewakeup(&sched.stopnote)
4820 }
4821 }
4822 unlock(&sched.lock)
4823 }
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837 func entersyscallblock() {
4838 gp := getg()
4839
4840 gp.m.locks++
4841 gp.throwsplit = true
4842 gp.stackguard0 = stackPreempt
4843 gp.m.syscalltick = gp.m.p.ptr().syscalltick
4844 gp.m.p.ptr().syscalltick++
4845
4846 addGSyscallNoP(gp.m)
4847
4848
4849 pc := sys.GetCallerPC()
4850 sp := sys.GetCallerSP()
4851 bp := getcallerfp()
4852 save(pc, sp, bp)
4853 gp.syscallsp = gp.sched.sp
4854 gp.syscallpc = gp.sched.pc
4855 gp.syscallbp = gp.sched.bp
4856 if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp {
4857 sp1 := sp
4858 sp2 := gp.sched.sp
4859 sp3 := gp.syscallsp
4860 systemstack(func() {
4861 print("entersyscallblock inconsistent sp ", hex(sp1), " ", hex(sp2), " ", hex(sp3), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
4862 throw("entersyscallblock")
4863 })
4864 }
4865
4866
4867
4868
4869
4870
4871 trace := traceAcquire()
4872 systemstack(func() {
4873 if trace.ok() {
4874 trace.GoSysCall()
4875 }
4876 handoffp(releasep())
4877 })
4878
4879
4880
4881 if debugExtendGrunningNoP {
4882 usleep(10)
4883 }
4884 casgstatus(gp, _Grunning, _Gsyscall)
4885 if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp {
4886 systemstack(func() {
4887 print("entersyscallblock inconsistent sp ", hex(sp), " ", hex(gp.sched.sp), " ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
4888 throw("entersyscallblock")
4889 })
4890 }
4891 if gp.syscallbp != 0 && gp.syscallbp < gp.stack.lo || gp.stack.hi < gp.syscallbp {
4892 systemstack(func() {
4893 print("entersyscallblock inconsistent bp ", hex(bp), " ", hex(gp.sched.bp), " ", hex(gp.syscallbp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n")
4894 throw("entersyscallblock")
4895 })
4896 }
4897 if trace.ok() {
4898 systemstack(func() {
4899 traceRelease(trace)
4900 })
4901 }
4902
4903
4904 save(sys.GetCallerPC(), sys.GetCallerSP(), getcallerfp())
4905
4906 gp.m.locks--
4907 }
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929 func exitsyscall() {
4930 gp := getg()
4931
4932 gp.m.locks++
4933 if sys.GetCallerSP() > gp.syscallsp {
4934 throw("exitsyscall: syscall frame is no longer valid")
4935 }
4936 gp.waitsince = 0
4937
4938 if sched.stopwait == freezeStopWait {
4939
4940
4941
4942 systemstack(func() {
4943 lock(&deadlock)
4944 lock(&deadlock)
4945 })
4946 }
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959 if gp.bubble != nil || !gp.atomicstatus.CompareAndSwap(_Gsyscall, _Grunning) {
4960 casgstatus(gp, _Gsyscall, _Grunning)
4961 }
4962
4963
4964
4965
4966 if debugExtendGrunningNoP {
4967 usleep(10)
4968 }
4969
4970
4971 oldp := gp.m.oldp.ptr()
4972 gp.m.oldp.set(nil)
4973
4974
4975 pp := gp.m.p.ptr()
4976 if pp != nil {
4977
4978 if trace := traceAcquire(); trace.ok() {
4979 systemstack(func() {
4980
4981
4982
4983
4984
4985
4986
4987
4988 if pp.syscalltick == gp.m.syscalltick {
4989 trace.GoSysExit(false)
4990 } else {
4991
4992
4993
4994
4995 trace.ProcSteal(pp)
4996 trace.ProcStart()
4997 trace.GoSysExit(true)
4998 trace.GoStart()
4999 }
5000 traceRelease(trace)
5001 })
5002 }
5003 } else {
5004
5005 systemstack(func() {
5006
5007 if pp := exitsyscallTryGetP(oldp); pp != nil {
5008
5009 acquirepNoTrace(pp)
5010
5011
5012 if trace := traceAcquire(); trace.ok() {
5013 trace.ProcStart()
5014 trace.GoSysExit(true)
5015 trace.GoStart()
5016 traceRelease(trace)
5017 }
5018 }
5019 })
5020 pp = gp.m.p.ptr()
5021 }
5022
5023
5024 if pp != nil {
5025 if goroutineProfile.active {
5026
5027
5028
5029 systemstack(func() {
5030 tryRecordGoroutineProfileWB(gp)
5031 })
5032 }
5033
5034
5035 pp.syscalltick++
5036
5037
5038
5039 gp.syscallsp = 0
5040 gp.m.locks--
5041 if gp.preempt {
5042
5043 gp.stackguard0 = stackPreempt
5044 } else {
5045
5046 gp.stackguard0 = gp.stack.lo + stackGuard
5047 }
5048 gp.throwsplit = false
5049
5050 if sched.disable.user && !schedEnabled(gp) {
5051
5052 Gosched()
5053 }
5054 return
5055 }
5056
5057 gp.m.locks--
5058
5059
5060 mcall(exitsyscallNoP)
5061
5062
5063
5064
5065
5066
5067
5068 gp.syscallsp = 0
5069 gp.m.p.ptr().syscalltick++
5070 gp.throwsplit = false
5071 }
5072
5073
5074
5075
5076
5077
5078
5079 func exitsyscallTryGetP(oldp *p) *p {
5080
5081 if oldp != nil {
5082 if thread, ok := setBlockOnExitSyscall(oldp); ok {
5083 thread.takeP()
5084 decGSyscallNoP(getg().m)
5085 thread.resume()
5086 return oldp
5087 }
5088 }
5089
5090
5091 if sched.pidle != 0 {
5092 lock(&sched.lock)
5093 pp, _ := pidleget(0)
5094 if pp != nil && sched.sysmonwait.Load() {
5095 sched.sysmonwait.Store(false)
5096 notewakeup(&sched.sysmonnote)
5097 }
5098 unlock(&sched.lock)
5099 if pp != nil {
5100 decGSyscallNoP(getg().m)
5101 return pp
5102 }
5103 }
5104 return nil
5105 }
5106
5107
5108
5109
5110
5111
5112
5113 func exitsyscallNoP(gp *g) {
5114 traceExitingSyscall()
5115 trace := traceAcquire()
5116 casgstatus(gp, _Grunning, _Grunnable)
5117 traceExitedSyscall()
5118 if trace.ok() {
5119
5120
5121
5122
5123 trace.GoSysExit(true)
5124 traceRelease(trace)
5125 }
5126 decGSyscallNoP(getg().m)
5127 dropg()
5128 lock(&sched.lock)
5129 var pp *p
5130 if schedEnabled(gp) {
5131 pp, _ = pidleget(0)
5132 }
5133 var locked bool
5134 if pp == nil {
5135 globrunqput(gp)
5136
5137
5138
5139
5140
5141
5142 locked = gp.lockedm != 0
5143 } else if sched.sysmonwait.Load() {
5144 sched.sysmonwait.Store(false)
5145 notewakeup(&sched.sysmonnote)
5146 }
5147 unlock(&sched.lock)
5148 if pp != nil {
5149 acquirep(pp)
5150 execute(gp, false)
5151 }
5152 if locked {
5153
5154
5155
5156
5157 stoplockedm()
5158 execute(gp, false)
5159 }
5160 stopm()
5161 schedule()
5162 }
5163
5164
5165
5166
5167
5168
5169
5170 func addGSyscallNoP(mp *m) {
5171
5172
5173
5174 if !mp.isExtraInC {
5175
5176
5177
5178
5179
5180 sched.nGsyscallNoP.Add(1)
5181 }
5182 }
5183
5184
5185
5186
5187
5188
5189
5190 func decGSyscallNoP(mp *m) {
5191
5192
5193
5194 if !mp.isExtraInC {
5195 sched.nGsyscallNoP.Add(-1)
5196 }
5197 }
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211 func syscall_runtime_BeforeFork() {
5212 gp := getg().m.curg
5213
5214
5215
5216
5217 gp.m.locks++
5218 sigsave(&gp.m.sigmask)
5219 sigblock(false)
5220
5221
5222
5223
5224
5225 gp.stackguard0 = stackFork
5226 }
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240 func syscall_runtime_AfterFork() {
5241 gp := getg().m.curg
5242
5243
5244 gp.stackguard0 = gp.stack.lo + stackGuard
5245
5246 msigrestore(gp.m.sigmask)
5247
5248 gp.m.locks--
5249 }
5250
5251
5252
5253 var inForkedChild bool
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274 func syscall_runtime_AfterForkInChild() {
5275
5276
5277
5278
5279 inForkedChild = true
5280
5281 clearSignalHandlers()
5282
5283
5284
5285 msigrestore(getg().m.sigmask)
5286
5287 inForkedChild = false
5288 }
5289
5290
5291
5292
5293 var pendingPreemptSignals atomic.Int32
5294
5295
5296
5297
5298 func syscall_runtime_BeforeExec() {
5299
5300 execLock.lock()
5301
5302
5303
5304 if GOOS == "darwin" || GOOS == "ios" {
5305 for pendingPreemptSignals.Load() > 0 {
5306 osyield()
5307 }
5308 }
5309 }
5310
5311
5312
5313
5314 func syscall_runtime_AfterExec() {
5315 execLock.unlock()
5316 }
5317
5318
5319 func malg(stacksize int32) *g {
5320 newg := new(g)
5321 if stacksize >= 0 {
5322 stacksize = round2(stackSystem + stacksize)
5323 systemstack(func() {
5324 newg.stack = stackalloc(uint32(stacksize))
5325 if valgrindenabled {
5326 newg.valgrindStackID = valgrindRegisterStack(unsafe.Pointer(newg.stack.lo), unsafe.Pointer(newg.stack.hi))
5327 }
5328 })
5329 newg.stackguard0 = newg.stack.lo + stackGuard
5330 newg.stackguard1 = ^uintptr(0)
5331
5332
5333 *(*uintptr)(unsafe.Pointer(newg.stack.lo)) = 0
5334 }
5335 return newg
5336 }
5337
5338
5339
5340
5341 func newproc(fn *funcval) {
5342 gp := getg()
5343 pc := sys.GetCallerPC()
5344 systemstack(func() {
5345 newg := newproc1(fn, gp, pc, false, waitReasonZero)
5346
5347 pp := getg().m.p.ptr()
5348 runqput(pp, newg, true)
5349
5350 if mainStarted {
5351 wakep()
5352 }
5353 })
5354 }
5355
5356
5357
5358
5359 func newproc1(fn *funcval, callergp *g, callerpc uintptr, parked bool, waitreason waitReason) *g {
5360 if fn == nil {
5361 fatal("go of nil func value")
5362 }
5363
5364 mp := acquirem()
5365 pp := mp.p.ptr()
5366 newg := gfget(pp)
5367 if newg == nil {
5368 newg = malg(stackMin)
5369 casgstatus(newg, _Gidle, _Gdead)
5370 allgadd(newg)
5371 }
5372 if newg.stack.hi == 0 {
5373 throw("newproc1: newg missing stack")
5374 }
5375
5376 if readgstatus(newg) != _Gdead {
5377 throw("newproc1: new g is not Gdead")
5378 }
5379
5380 totalSize := uintptr(4*goarch.PtrSize + sys.MinFrameSize)
5381 totalSize = alignUp(totalSize, sys.StackAlign)
5382 sp := newg.stack.hi - totalSize
5383 if usesLR {
5384
5385 *(*uintptr)(unsafe.Pointer(sp)) = 0
5386 prepGoExitFrame(sp)
5387 }
5388 if GOARCH == "arm64" {
5389
5390 *(*uintptr)(unsafe.Pointer(sp - goarch.PtrSize)) = 0
5391 }
5392
5393 memclrNoHeapPointers(unsafe.Pointer(&newg.sched), unsafe.Sizeof(newg.sched))
5394 newg.sched.sp = sp
5395 newg.stktopsp = sp
5396 newg.sched.pc = abi.FuncPCABI0(goexit) + sys.PCQuantum
5397 newg.sched.g = guintptr(unsafe.Pointer(newg))
5398 gostartcallfn(&newg.sched, fn)
5399 newg.parentGoid = callergp.goid
5400 newg.gopc = callerpc
5401 newg.ancestors = saveAncestors(callergp)
5402 newg.startpc = fn.fn
5403 newg.runningCleanups.Store(false)
5404 if isSystemGoroutine(newg, false) {
5405 sched.ngsys.Add(1)
5406 } else {
5407
5408 newg.bubble = callergp.bubble
5409 if mp.curg != nil {
5410 newg.labels = mp.curg.labels
5411 }
5412 if goroutineProfile.active {
5413
5414
5415
5416
5417
5418 newg.goroutineProfiled.Store(goroutineProfileSatisfied)
5419 }
5420 }
5421
5422 newg.trackingSeq = uint8(cheaprand())
5423 if newg.trackingSeq%gTrackingPeriod == 0 {
5424 newg.tracking = true
5425 }
5426 gcController.addScannableStack(pp, int64(newg.stack.hi-newg.stack.lo))
5427
5428
5429
5430 trace := traceAcquire()
5431 var status uint32 = _Grunnable
5432 if parked {
5433 status = _Gwaiting
5434 newg.waitreason = waitreason
5435 }
5436 if pp.goidcache == pp.goidcacheend {
5437
5438
5439
5440 pp.goidcache = sched.goidgen.Add(_GoidCacheBatch)
5441 pp.goidcache -= _GoidCacheBatch - 1
5442 pp.goidcacheend = pp.goidcache + _GoidCacheBatch
5443 }
5444 newg.goid = pp.goidcache
5445 casgstatus(newg, _Gdead, status)
5446 pp.goidcache++
5447 newg.trace.reset()
5448 if trace.ok() {
5449 trace.GoCreate(newg, newg.startpc, parked)
5450 traceRelease(trace)
5451 }
5452
5453
5454 newg.fipsOnlyBypass = callergp.fipsOnlyBypass
5455
5456
5457 newg.ditWanted = callergp.ditWanted
5458
5459 if goexperiment.RuntimeSecret && callergp.secret > 0 {
5460
5461
5462
5463
5464
5465
5466
5467
5468 newg.secret = 1
5469 }
5470
5471
5472 if raceenabled {
5473 newg.racectx = racegostart(callerpc)
5474 newg.raceignore = 0
5475 if newg.labels != nil {
5476
5477
5478 racereleasemergeg(newg, unsafe.Pointer(&labelSync))
5479 }
5480 }
5481 pp.goroutinesCreated++
5482 releasem(mp)
5483
5484 return newg
5485 }
5486
5487
5488
5489
5490 func saveAncestors(callergp *g) *[]ancestorInfo {
5491
5492 if debug.tracebackancestors <= 0 || callergp.goid == 0 {
5493 return nil
5494 }
5495 var callerAncestors []ancestorInfo
5496 if callergp.ancestors != nil {
5497 callerAncestors = *callergp.ancestors
5498 }
5499 n := int32(len(callerAncestors)) + 1
5500 if n > debug.tracebackancestors {
5501 n = debug.tracebackancestors
5502 }
5503 ancestors := make([]ancestorInfo, n)
5504 copy(ancestors[1:], callerAncestors)
5505
5506 var pcs [tracebackInnerFrames]uintptr
5507 npcs := gcallers(callergp, 0, pcs[:])
5508 ipcs := make([]uintptr, npcs)
5509 copy(ipcs, pcs[:])
5510 ancestors[0] = ancestorInfo{
5511 pcs: ipcs,
5512 goid: callergp.goid,
5513 gopc: callergp.gopc,
5514 }
5515
5516 ancestorsp := new([]ancestorInfo)
5517 *ancestorsp = ancestors
5518 return ancestorsp
5519 }
5520
5521
5522
5523 func gfput(pp *p, gp *g) {
5524 if readgstatus(gp) != _Gdead {
5525 throw("gfput: bad status (not Gdead)")
5526 }
5527
5528 stksize := gp.stack.hi - gp.stack.lo
5529
5530 if stksize != uintptr(startingStackSize) {
5531
5532 stackfree(gp.stack)
5533 gp.stack.lo = 0
5534 gp.stack.hi = 0
5535 gp.stackguard0 = 0
5536 if valgrindenabled {
5537 valgrindDeregisterStack(gp.valgrindStackID)
5538 gp.valgrindStackID = 0
5539 }
5540 }
5541
5542 pp.gFree.push(gp)
5543 if pp.gFree.size >= 64 {
5544 var (
5545 stackQ gQueue
5546 noStackQ gQueue
5547 )
5548 for pp.gFree.size >= 32 {
5549 gp := pp.gFree.pop()
5550 if gp.stack.lo == 0 {
5551 noStackQ.push(gp)
5552 } else {
5553 stackQ.push(gp)
5554 }
5555 }
5556 lock(&sched.gFree.lock)
5557 sched.gFree.noStack.pushAll(noStackQ)
5558 sched.gFree.stack.pushAll(stackQ)
5559 unlock(&sched.gFree.lock)
5560 }
5561 }
5562
5563
5564
5565 func gfget(pp *p) *g {
5566 retry:
5567 if pp.gFree.empty() && (!sched.gFree.stack.empty() || !sched.gFree.noStack.empty()) {
5568 lock(&sched.gFree.lock)
5569
5570 for pp.gFree.size < 32 {
5571
5572 gp := sched.gFree.stack.pop()
5573 if gp == nil {
5574 gp = sched.gFree.noStack.pop()
5575 if gp == nil {
5576 break
5577 }
5578 }
5579 pp.gFree.push(gp)
5580 }
5581 unlock(&sched.gFree.lock)
5582 goto retry
5583 }
5584 gp := pp.gFree.pop()
5585 if gp == nil {
5586 return nil
5587 }
5588 if gp.stack.lo != 0 && gp.stack.hi-gp.stack.lo != uintptr(startingStackSize) {
5589
5590
5591
5592 systemstack(func() {
5593 stackfree(gp.stack)
5594 gp.stack.lo = 0
5595 gp.stack.hi = 0
5596 gp.stackguard0 = 0
5597 if valgrindenabled {
5598 valgrindDeregisterStack(gp.valgrindStackID)
5599 gp.valgrindStackID = 0
5600 }
5601 })
5602 }
5603 if gp.stack.lo == 0 {
5604
5605 systemstack(func() {
5606 gp.stack = stackalloc(startingStackSize)
5607 if valgrindenabled {
5608 gp.valgrindStackID = valgrindRegisterStack(unsafe.Pointer(gp.stack.lo), unsafe.Pointer(gp.stack.hi))
5609 }
5610 })
5611 gp.stackguard0 = gp.stack.lo + stackGuard
5612 } else {
5613 if raceenabled {
5614 racemalloc(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo)
5615 }
5616 if msanenabled {
5617 msanmalloc(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo)
5618 }
5619 if asanenabled {
5620 asanunpoison(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo)
5621 }
5622 }
5623 return gp
5624 }
5625
5626
5627 func gfpurge(pp *p) {
5628 var (
5629 stackQ gQueue
5630 noStackQ gQueue
5631 )
5632 for !pp.gFree.empty() {
5633 gp := pp.gFree.pop()
5634 if gp.stack.lo == 0 {
5635 noStackQ.push(gp)
5636 } else {
5637 stackQ.push(gp)
5638 }
5639 }
5640 lock(&sched.gFree.lock)
5641 sched.gFree.noStack.pushAll(noStackQ)
5642 sched.gFree.stack.pushAll(stackQ)
5643 unlock(&sched.gFree.lock)
5644 }
5645
5646
5647 func Breakpoint() {
5648 breakpoint()
5649 }
5650
5651
5652
5653
5654
5655
5656 func dolockOSThread() {
5657 if GOARCH == "wasm" {
5658 return
5659 }
5660 gp := getg()
5661 gp.m.lockedg.set(gp)
5662 gp.lockedm.set(gp.m)
5663 }
5664
5665
5666
5667
5668
5669
5670
5671
5672
5673
5674
5675
5676
5677
5678
5679
5680
5681 func LockOSThread() {
5682 if atomic.Load(&newmHandoff.haveTemplateThread) == 0 && GOOS != "plan9" {
5683
5684
5685
5686 startTemplateThread()
5687 }
5688 gp := getg()
5689 gp.m.lockedExt++
5690 if gp.m.lockedExt == 0 {
5691 gp.m.lockedExt--
5692 panic("LockOSThread nesting overflow")
5693 }
5694 dolockOSThread()
5695 }
5696
5697
5698 func lockOSThread() {
5699 getg().m.lockedInt++
5700 dolockOSThread()
5701 }
5702
5703
5704
5705
5706
5707
5708 func dounlockOSThread() {
5709 if GOARCH == "wasm" {
5710 return
5711 }
5712 gp := getg()
5713 if gp.m.lockedInt != 0 || gp.m.lockedExt != 0 {
5714 return
5715 }
5716 gp.m.lockedg = 0
5717 gp.lockedm = 0
5718 }
5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
5731
5732
5733
5734 func UnlockOSThread() {
5735 gp := getg()
5736 if gp.m.lockedExt == 0 {
5737 return
5738 }
5739 gp.m.lockedExt--
5740 dounlockOSThread()
5741 }
5742
5743
5744 func unlockOSThread() {
5745 gp := getg()
5746 if gp.m.lockedInt == 0 {
5747 systemstack(badunlockosthread)
5748 }
5749 gp.m.lockedInt--
5750 dounlockOSThread()
5751 }
5752
5753 func badunlockosthread() {
5754 throw("runtime: internal error: misuse of lockOSThread/unlockOSThread")
5755 }
5756
5757 func gcount(includeSys bool) int32 {
5758 n := int32(atomic.Loaduintptr(&allglen)) - sched.gFree.stack.size - sched.gFree.noStack.size
5759 if !includeSys {
5760 n -= sched.ngsys.Load()
5761 }
5762 for _, pp := range allp {
5763 n -= pp.gFree.size
5764 }
5765
5766
5767
5768 if n < 1 {
5769 n = 1
5770 }
5771 return n
5772 }
5773
5774
5775
5776
5777
5778 func goroutineleakcount() int {
5779 return work.goroutineLeak.count
5780 }
5781
5782 func mcount() int32 {
5783 return int32(sched.mnext - sched.nmfreed)
5784 }
5785
5786 var prof struct {
5787 signalLock atomic.Uint32
5788
5789
5790
5791 hz atomic.Int32
5792 }
5793
5794 func _System() { _System() }
5795 func _ExternalCode() { _ExternalCode() }
5796 func _LostExternalCode() { _LostExternalCode() }
5797 func _GC() { _GC() }
5798 func _LostSIGPROFDuringAtomic64() { _LostSIGPROFDuringAtomic64() }
5799 func _LostContendedRuntimeLock() { _LostContendedRuntimeLock() }
5800 func _VDSO() { _VDSO() }
5801
5802
5803
5804
5805
5806 func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
5807 if prof.hz.Load() == 0 {
5808 return
5809 }
5810
5811
5812
5813
5814 if mp != nil && mp.profilehz == 0 {
5815 return
5816 }
5817
5818
5819
5820
5821
5822
5823
5824 if GOARCH == "mips" || GOARCH == "mipsle" || GOARCH == "arm" {
5825 if f := findfunc(pc); f.valid() {
5826 if stringslite.HasPrefix(funcname(f), "internal/runtime/atomic") {
5827 cpuprof.lostAtomic++
5828 return
5829 }
5830 }
5831 if GOARCH == "arm" && goarm < 7 && GOOS == "linux" && pc&0xffff0000 == 0xffff0000 {
5832
5833
5834
5835 cpuprof.lostAtomic++
5836 return
5837 }
5838 }
5839
5840
5841
5842
5843
5844
5845
5846 getg().m.mallocing++
5847
5848 var u unwinder
5849 var stk [maxCPUProfStack]uintptr
5850 n := 0
5851 if mp.ncgo > 0 && mp.curg != nil && mp.curg.syscallpc != 0 && mp.curg.syscallsp != 0 {
5852 cgoOff := 0
5853
5854
5855
5856
5857
5858 if mp.cgoCallersUse.Load() == 0 && mp.cgoCallers != nil && mp.cgoCallers[0] != 0 {
5859 for cgoOff < len(mp.cgoCallers) && mp.cgoCallers[cgoOff] != 0 {
5860 cgoOff++
5861 }
5862 n += copy(stk[:], mp.cgoCallers[:cgoOff])
5863 mp.cgoCallers[0] = 0
5864 }
5865
5866
5867 u.initAt(mp.curg.syscallpc, mp.curg.syscallsp, 0, mp.curg, unwindSilentErrors)
5868 } else if usesLibcall() && mp.libcallg != 0 && mp.libcallpc != 0 && mp.libcallsp != 0 {
5869
5870
5871 u.initAt(mp.libcallpc, mp.libcallsp, 0, mp.libcallg.ptr(), unwindSilentErrors)
5872 } else if mp != nil && mp.vdsoSP != 0 {
5873
5874
5875 u.initAt(mp.vdsoPC, mp.vdsoSP, 0, gp, unwindSilentErrors|unwindJumpStack)
5876 } else {
5877 u.initAt(pc, sp, lr, gp, unwindSilentErrors|unwindTrap|unwindJumpStack)
5878 }
5879 n += tracebackPCs(&u, 0, stk[n:])
5880
5881 if n <= 0 {
5882
5883
5884 n = 2
5885 if inVDSOPage(pc) {
5886 pc = abi.FuncPCABIInternal(_VDSO) + sys.PCQuantum
5887 } else if pc > firstmoduledata.etext {
5888
5889 pc = abi.FuncPCABIInternal(_ExternalCode) + sys.PCQuantum
5890 }
5891 stk[0] = pc
5892 if mp.preemptoff != "" {
5893 stk[1] = abi.FuncPCABIInternal(_GC) + sys.PCQuantum
5894 } else {
5895 stk[1] = abi.FuncPCABIInternal(_System) + sys.PCQuantum
5896 }
5897 }
5898
5899 if prof.hz.Load() != 0 {
5900
5901
5902
5903 var tagPtr *unsafe.Pointer
5904 if gp != nil && gp.m != nil && gp.m.curg != nil {
5905 tagPtr = &gp.m.curg.labels
5906 }
5907 cpuprof.add(tagPtr, stk[:n])
5908
5909 gprof := gp
5910 var mp *m
5911 var pp *p
5912 if gp != nil && gp.m != nil {
5913 if gp.m.curg != nil {
5914 gprof = gp.m.curg
5915 }
5916 mp = gp.m
5917 pp = gp.m.p.ptr()
5918 }
5919 traceCPUSample(gprof, mp, pp, stk[:n])
5920 }
5921 getg().m.mallocing--
5922 }
5923
5924
5925
5926 func setcpuprofilerate(hz int32) {
5927
5928 if hz < 0 {
5929 hz = 0
5930 }
5931
5932
5933
5934 gp := getg()
5935 gp.m.locks++
5936
5937
5938
5939
5940 setThreadCPUProfiler(0)
5941
5942 for !prof.signalLock.CompareAndSwap(0, 1) {
5943 osyield()
5944 }
5945 if prof.hz.Load() != hz {
5946 setProcessCPUProfiler(hz)
5947 prof.hz.Store(hz)
5948 }
5949 prof.signalLock.Store(0)
5950
5951 lock(&sched.lock)
5952 sched.profilehz = hz
5953 unlock(&sched.lock)
5954
5955 if hz != 0 {
5956 setThreadCPUProfiler(hz)
5957 }
5958
5959 gp.m.locks--
5960 }
5961
5962
5963
5964 func (pp *p) init(id int32) {
5965 pp.id = id
5966 pp.gcw.id = id
5967 pp.status = _Pgcstop
5968 pp.sudogcache = pp.sudogbuf[:0]
5969 pp.deferpool = pp.deferpoolbuf[:0]
5970 pp.wbBuf.reset()
5971 if pp.mcache == nil {
5972 if id == 0 {
5973 if mcache0 == nil {
5974 throw("missing mcache?")
5975 }
5976
5977
5978 pp.mcache = mcache0
5979 } else {
5980 pp.mcache = allocmcache()
5981 }
5982 }
5983 if raceenabled && pp.raceprocctx == 0 {
5984 if id == 0 {
5985 pp.raceprocctx = raceprocctx0
5986 raceprocctx0 = 0
5987 } else {
5988 pp.raceprocctx = raceproccreate()
5989 }
5990 }
5991 lockInit(&pp.timers.mu, lockRankTimers)
5992
5993
5994
5995 timerpMask.set(id)
5996
5997
5998 idlepMask.clear(id)
5999 }
6000
6001
6002
6003
6004
6005 func (pp *p) destroy() {
6006 assertLockHeld(&sched.lock)
6007 assertWorldStopped()
6008
6009
6010 for pp.runqhead != pp.runqtail {
6011
6012 pp.runqtail--
6013 gp := pp.runq[pp.runqtail%uint32(len(pp.runq))].ptr()
6014
6015 globrunqputhead(gp)
6016 }
6017 if pp.runnext != 0 {
6018 globrunqputhead(pp.runnext.ptr())
6019 pp.runnext = 0
6020 }
6021
6022
6023 getg().m.p.ptr().timers.take(&pp.timers)
6024
6025
6026
6027 if phase := gcphase; phase != _GCoff {
6028 println("runtime: p id", pp.id, "destroyed during GC phase", phase)
6029 throw("P destroyed while GC is running")
6030 }
6031
6032 pp.gcw.spanq.destroy()
6033
6034 clear(pp.sudogbuf[:])
6035 pp.sudogcache = pp.sudogbuf[:0]
6036 pp.pinnerCache = nil
6037 if pp.pinCounterCache != nil {
6038 lock(&mheap_.speciallock)
6039 mheap_.specialPinCounterAlloc.free(unsafe.Pointer(pp.pinCounterCache))
6040 unlock(&mheap_.speciallock)
6041 pp.pinCounterCache = nil
6042 }
6043 clear(pp.deferpoolbuf[:])
6044 pp.deferpool = pp.deferpoolbuf[:0]
6045 systemstack(func() {
6046 for i := 0; i < pp.mspancache.len; i++ {
6047
6048 mheap_.spanalloc.free(unsafe.Pointer(pp.mspancache.buf[i]))
6049 }
6050 pp.mspancache.len = 0
6051 lock(&mheap_.lock)
6052 pp.pcache.flush(&mheap_.pages)
6053 unlock(&mheap_.lock)
6054 })
6055 freemcache(pp.mcache)
6056 pp.mcache = nil
6057 gfpurge(pp)
6058 if raceenabled {
6059 if pp.timers.raceCtx != 0 {
6060
6061
6062
6063
6064
6065 mp := getg().m
6066 phold := mp.p.ptr()
6067 mp.p.set(pp)
6068
6069 racectxend(pp.timers.raceCtx)
6070 pp.timers.raceCtx = 0
6071
6072 mp.p.set(phold)
6073 }
6074 raceprocdestroy(pp.raceprocctx)
6075 pp.raceprocctx = 0
6076 }
6077 pp.gcAssistTime = 0
6078 gcCleanups.queued += pp.cleanupsQueued
6079 pp.cleanupsQueued = 0
6080 sched.goroutinesCreated.Add(int64(pp.goroutinesCreated))
6081 pp.goroutinesCreated = 0
6082 pp.xRegs.free()
6083 pp.status = _Pdead
6084 }
6085
6086
6087
6088
6089
6090
6091
6092
6093
6094 func procresize(nprocs int32) *p {
6095 assertLockHeld(&sched.lock)
6096 assertWorldStopped()
6097
6098 old := gomaxprocs
6099 if old < 0 || nprocs <= 0 {
6100 throw("procresize: invalid arg")
6101 }
6102 trace := traceAcquire()
6103 if trace.ok() {
6104 trace.Gomaxprocs(nprocs)
6105 traceRelease(trace)
6106 }
6107
6108
6109 now := nanotime()
6110 if sched.procresizetime != 0 {
6111 sched.totaltime += int64(old) * (now - sched.procresizetime)
6112 }
6113 sched.procresizetime = now
6114
6115
6116 if nprocs > int32(len(allp)) {
6117
6118
6119 lock(&allpLock)
6120 if nprocs <= int32(cap(allp)) {
6121 allp = allp[:nprocs]
6122 } else {
6123 nallp := make([]*p, nprocs)
6124
6125
6126 copy(nallp, allp[:cap(allp)])
6127 allp = nallp
6128 }
6129
6130 idlepMask = idlepMask.resize(nprocs)
6131 timerpMask = timerpMask.resize(nprocs)
6132 work.spanqMask = work.spanqMask.resize(nprocs)
6133 unlock(&allpLock)
6134 }
6135
6136
6137 for i := old; i < nprocs; i++ {
6138 pp := allp[i]
6139 if pp == nil {
6140 pp = new(p)
6141 }
6142 pp.init(i)
6143 atomicstorep(unsafe.Pointer(&allp[i]), unsafe.Pointer(pp))
6144 }
6145
6146 gp := getg()
6147 if gp.m.p != 0 && gp.m.p.ptr().id < nprocs {
6148
6149 gp.m.p.ptr().status = _Prunning
6150 gp.m.p.ptr().mcache.prepareForSweep()
6151 } else {
6152
6153
6154
6155
6156
6157 if gp.m.p != 0 {
6158 trace := traceAcquire()
6159 if trace.ok() {
6160
6161
6162
6163 trace.GoSched()
6164 trace.ProcStop(gp.m.p.ptr())
6165 traceRelease(trace)
6166 }
6167 gp.m.p.ptr().m = 0
6168 }
6169 gp.m.p = 0
6170 pp := allp[0]
6171 pp.m = 0
6172 pp.status = _Pidle
6173 acquirep(pp)
6174 trace := traceAcquire()
6175 if trace.ok() {
6176 trace.GoStart()
6177 traceRelease(trace)
6178 }
6179 }
6180
6181
6182 mcache0 = nil
6183
6184
6185 for i := nprocs; i < old; i++ {
6186 pp := allp[i]
6187 pp.destroy()
6188
6189 }
6190
6191
6192 if int32(len(allp)) != nprocs {
6193 lock(&allpLock)
6194 allp = allp[:nprocs]
6195 idlepMask = idlepMask.resize(nprocs)
6196 timerpMask = timerpMask.resize(nprocs)
6197 work.spanqMask = work.spanqMask.resize(nprocs)
6198 unlock(&allpLock)
6199 }
6200
6201
6202 var runnablePs *p
6203 var runnablePsNeedM *p
6204 var idlePs *p
6205 for i := nprocs - 1; i >= 0; i-- {
6206 pp := allp[i]
6207 if gp.m.p.ptr() == pp {
6208 continue
6209 }
6210 pp.status = _Pidle
6211 if runqempty(pp) {
6212 pp.link.set(idlePs)
6213 idlePs = pp
6214 continue
6215 }
6216
6217
6218
6219
6220
6221
6222
6223
6224 var mp *m
6225 if oldm := pp.oldm.get(); oldm != nil {
6226
6227 mp = mgetSpecific(oldm)
6228 }
6229 if mp == nil {
6230
6231 pp.link.set(runnablePsNeedM)
6232 runnablePsNeedM = pp
6233 continue
6234 }
6235 pp.m.set(mp)
6236 pp.link.set(runnablePs)
6237 runnablePs = pp
6238 }
6239
6240
6241 for runnablePsNeedM != nil {
6242 pp := runnablePsNeedM
6243 runnablePsNeedM = pp.link.ptr()
6244
6245 mp := mget()
6246 pp.m.set(mp)
6247 pp.link.set(runnablePs)
6248 runnablePs = pp
6249 }
6250
6251
6252
6253
6254
6255
6256
6257
6258
6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
6269
6270
6271
6272
6273
6274
6275 if gcBlackenEnabled != 0 {
6276 for idlePs != nil {
6277 pp := idlePs
6278
6279 ok, _ := gcController.assignWaitingGCWorker(pp, now)
6280 if !ok {
6281
6282 break
6283 }
6284
6285
6286
6287
6288
6289
6290
6291
6292 idlePs = pp.link.ptr()
6293 mp := mget()
6294 pp.m.set(mp)
6295 pp.link.set(runnablePs)
6296 runnablePs = pp
6297 }
6298 }
6299
6300
6301 for idlePs != nil {
6302 pp := idlePs
6303 idlePs = pp.link.ptr()
6304 pidleput(pp, now)
6305 }
6306
6307 stealOrder.reset(uint32(nprocs))
6308 var int32p *int32 = &gomaxprocs
6309 atomic.Store((*uint32)(unsafe.Pointer(int32p)), uint32(nprocs))
6310 if old != nprocs {
6311
6312 gcCPULimiter.resetCapacity(now, nprocs)
6313 }
6314 return runnablePs
6315 }
6316
6317
6318
6319
6320
6321
6322
6323 func acquirep(pp *p) {
6324
6325 acquirepNoTrace(pp)
6326
6327
6328 trace := traceAcquire()
6329 if trace.ok() {
6330 trace.ProcStart()
6331 traceRelease(trace)
6332 }
6333 }
6334
6335
6336
6337
6338 func acquirepNoTrace(pp *p) {
6339
6340 wirep(pp)
6341
6342
6343
6344
6345
6346
6347 pp.oldm = pp.m.ptr().self
6348
6349
6350
6351 pp.mcache.prepareForSweep()
6352 }
6353
6354
6355
6356
6357
6358
6359
6360 func wirep(pp *p) {
6361 gp := getg()
6362
6363 if gp.m.p != 0 {
6364
6365
6366 systemstack(func() {
6367 throw("wirep: already in go")
6368 })
6369 }
6370 if pp.m != 0 || pp.status != _Pidle {
6371
6372
6373 systemstack(func() {
6374 id := int64(0)
6375 if pp.m != 0 {
6376 id = pp.m.ptr().id
6377 }
6378 print("wirep: p->m=", pp.m, "(", id, ") p->status=", pp.status, "\n")
6379 throw("wirep: invalid p state")
6380 })
6381 }
6382 gp.m.p.set(pp)
6383 pp.m.set(gp.m)
6384 pp.status = _Prunning
6385 }
6386
6387
6388 func releasep() *p {
6389 trace := traceAcquire()
6390 if trace.ok() {
6391 trace.ProcStop(getg().m.p.ptr())
6392 traceRelease(trace)
6393 }
6394 return releasepNoTrace()
6395 }
6396
6397
6398 func releasepNoTrace() *p {
6399 gp := getg()
6400
6401 if gp.m.p == 0 {
6402 throw("releasep: invalid arg")
6403 }
6404 pp := gp.m.p.ptr()
6405 if pp.m.ptr() != gp.m || pp.status != _Prunning {
6406 print("releasep: m=", gp.m, " m->p=", gp.m.p.ptr(), " p->m=", hex(pp.m), " p->status=", pp.status, "\n")
6407 throw("releasep: invalid p state")
6408 }
6409
6410
6411 gcController.releaseNextGCMarkWorker(pp)
6412
6413 gp.m.p = 0
6414 pp.m = 0
6415 pp.status = _Pidle
6416 return pp
6417 }
6418
6419 func incidlelocked(v int32) {
6420 lock(&sched.lock)
6421 sched.nmidlelocked += v
6422 if v > 0 {
6423 checkdead()
6424 }
6425 unlock(&sched.lock)
6426 }
6427
6428
6429
6430
6431 func checkdead() {
6432 assertLockHeld(&sched.lock)
6433
6434
6435
6436
6437
6438
6439 if (islibrary || isarchive) && GOARCH != "wasm" {
6440 return
6441 }
6442
6443
6444
6445
6446
6447 if panicking.Load() > 0 {
6448 return
6449 }
6450
6451
6452
6453
6454
6455 var run0 int32
6456 if !iscgo && cgoHasExtraM && extraMLength.Load() > 0 {
6457 run0 = 1
6458 }
6459
6460 run := mcount() - sched.nmidle - sched.nmidlelocked - sched.nmsys
6461 if run > run0 {
6462 return
6463 }
6464 if run < 0 {
6465 print("runtime: checkdead: nmidle=", sched.nmidle, " nmidlelocked=", sched.nmidlelocked, " mcount=", mcount(), " nmsys=", sched.nmsys, "\n")
6466 unlock(&sched.lock)
6467 throw("checkdead: inconsistent counts")
6468 }
6469
6470 grunning := 0
6471 forEachG(func(gp *g) {
6472 if isSystemGoroutine(gp, false) {
6473 return
6474 }
6475 s := readgstatus(gp)
6476 switch s &^ _Gscan {
6477 case _Gwaiting,
6478 _Gpreempted:
6479 grunning++
6480 case _Grunnable,
6481 _Grunning,
6482 _Gsyscall:
6483 print("runtime: checkdead: find g ", gp.goid, " in status ", s, "\n")
6484 unlock(&sched.lock)
6485 throw("checkdead: runnable g")
6486 }
6487 })
6488 if grunning == 0 {
6489 unlock(&sched.lock)
6490 fatal("no goroutines (main called runtime.Goexit) - deadlock!")
6491 }
6492
6493
6494 if faketime != 0 {
6495 if when := timeSleepUntil(); when < maxWhen {
6496 faketime = when
6497
6498
6499 pp, _ := pidleget(faketime)
6500 if pp == nil {
6501
6502
6503 unlock(&sched.lock)
6504 throw("checkdead: no p for timer")
6505 }
6506 mp := mget()
6507 if mp == nil {
6508
6509
6510 unlock(&sched.lock)
6511 throw("checkdead: no m for timer")
6512 }
6513
6514
6515
6516 sched.nmspinning.Add(1)
6517 mp.spinning = true
6518 mp.nextp.set(pp)
6519 notewakeup(&mp.park)
6520 return
6521 }
6522 }
6523
6524
6525 for _, pp := range allp {
6526 if len(pp.timers.heap) > 0 {
6527 return
6528 }
6529 }
6530
6531 unlock(&sched.lock)
6532 fatal("all goroutines are asleep - deadlock!")
6533 }
6534
6535
6536
6537
6538
6539
6540 var forcegcperiod int64 = 2 * 60 * 1e9
6541
6542
6543
6544
6545 const haveSysmon = GOARCH != "wasm"
6546
6547
6548
6549
6550 func sysmon() {
6551 lock(&sched.lock)
6552 sched.nmsys++
6553 checkdead()
6554 unlock(&sched.lock)
6555
6556 lastgomaxprocs := int64(0)
6557 lasttrace := int64(0)
6558 idle := 0
6559 delay := uint32(0)
6560
6561 for {
6562 if idle == 0 {
6563 delay = 20
6564 } else if idle > 50 {
6565 delay *= 2
6566 }
6567 if delay > 10*1000 {
6568 delay = 10 * 1000
6569 }
6570 usleep(delay)
6571
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584
6585
6586
6587 now := nanotime()
6588 if debug.schedtrace <= 0 && (sched.gcwaiting.Load() || sched.npidle.Load() == gomaxprocs) {
6589 lock(&sched.lock)
6590 if sched.gcwaiting.Load() || sched.npidle.Load() == gomaxprocs {
6591 syscallWake := false
6592 next := timeSleepUntil()
6593 if next > now {
6594 sched.sysmonwait.Store(true)
6595 unlock(&sched.lock)
6596
6597
6598 sleep := forcegcperiod / 2
6599 if next-now < sleep {
6600 sleep = next - now
6601 }
6602 shouldRelax := sleep >= osRelaxMinNS
6603 if shouldRelax {
6604 osRelax(true)
6605 }
6606 syscallWake = notetsleep(&sched.sysmonnote, sleep)
6607 if shouldRelax {
6608 osRelax(false)
6609 }
6610 lock(&sched.lock)
6611 sched.sysmonwait.Store(false)
6612 noteclear(&sched.sysmonnote)
6613 }
6614 if syscallWake {
6615 idle = 0
6616 delay = 20
6617 }
6618 }
6619 unlock(&sched.lock)
6620 }
6621
6622 lock(&sched.sysmonlock)
6623
6624
6625 now = nanotime()
6626
6627
6628 if *cgo_yield != nil {
6629 asmcgocall(*cgo_yield, nil)
6630 }
6631
6632 lastpoll := sched.lastpoll.Load()
6633 if netpollinited() && lastpoll != 0 && lastpoll+10*1000*1000 < now {
6634 sched.lastpoll.CompareAndSwap(lastpoll, now)
6635 list, delta := netpoll(0)
6636 if !list.empty() {
6637
6638
6639
6640
6641
6642
6643
6644 incidlelocked(-1)
6645 injectglist(&list)
6646 incidlelocked(1)
6647 netpollAdjustWaiters(delta)
6648 }
6649 }
6650
6651 if debug.updatemaxprocs != 0 && lastgomaxprocs+1e9 <= now {
6652 sysmonUpdateGOMAXPROCS()
6653 lastgomaxprocs = now
6654 }
6655 if scavenger.sysmonWake.Load() != 0 {
6656
6657 scavenger.wake()
6658 }
6659
6660
6661 if retake(now) != 0 {
6662 idle = 0
6663 } else {
6664 idle++
6665 }
6666
6667 if t := (gcTrigger{kind: gcTriggerTime, now: now}); t.test() && forcegc.idle.Load() {
6668 lock(&forcegc.lock)
6669 forcegc.idle.Store(false)
6670 var list gList
6671 list.push(forcegc.g)
6672 injectglist(&list)
6673 unlock(&forcegc.lock)
6674 }
6675 if debug.schedtrace > 0 && lasttrace+int64(debug.schedtrace)*1000000 <= now {
6676 lasttrace = now
6677 schedtrace(debug.scheddetail > 0)
6678 }
6679 unlock(&sched.sysmonlock)
6680 }
6681 }
6682
6683 type sysmontick struct {
6684 schedtick uint32
6685 syscalltick uint32
6686 schedwhen int64
6687 syscallwhen int64
6688 }
6689
6690
6691
6692 const forcePreemptNS = 10 * 1000 * 1000
6693
6694 func retake(now int64) uint32 {
6695 n := 0
6696
6697
6698 lock(&allpLock)
6699
6700
6701
6702 for i := 0; i < len(allp); i++ {
6703
6704
6705
6706
6707
6708
6709
6710
6711 pp := allp[i]
6712 if pp == nil || atomic.Load(&pp.status) != _Prunning {
6713
6714
6715 continue
6716 }
6717 pd := &pp.sysmontick
6718 sysretake := false
6719
6720
6721
6722
6723
6724 schedt := int64(pp.schedtick)
6725 if int64(pd.schedtick) != schedt {
6726 pd.schedtick = uint32(schedt)
6727 pd.schedwhen = now
6728 } else if pd.schedwhen+forcePreemptNS <= now {
6729 preemptone(pp)
6730
6731
6732
6733
6734 sysretake = true
6735 }
6736
6737
6738 unlock(&allpLock)
6739
6740
6741
6742
6743
6744
6745
6746
6747 incidlelocked(-1)
6748
6749
6750 thread, ok := setBlockOnExitSyscall(pp)
6751 if !ok {
6752
6753 goto done
6754 }
6755
6756
6757 if syst := int64(pp.syscalltick); !sysretake && int64(pd.syscalltick) != syst {
6758 pd.syscalltick = uint32(syst)
6759 pd.syscallwhen = now
6760 thread.resume()
6761 goto done
6762 }
6763
6764
6765
6766
6767 if runqempty(pp) && sched.nmspinning.Load()+sched.npidle.Load() > 0 && pd.syscallwhen+10*1000*1000 > now {
6768 thread.resume()
6769 goto done
6770 }
6771
6772
6773
6774 thread.takeP()
6775 thread.resume()
6776 n++
6777
6778
6779 handoffp(pp)
6780
6781
6782
6783 done:
6784 incidlelocked(1)
6785 lock(&allpLock)
6786 }
6787 unlock(&allpLock)
6788 return uint32(n)
6789 }
6790
6791
6792
6793 type syscallingThread struct {
6794 gp *g
6795 mp *m
6796 pp *p
6797 status uint32
6798 }
6799
6800
6801
6802
6803
6804
6805
6806
6807
6808
6809
6810
6811
6812
6813
6814 func setBlockOnExitSyscall(pp *p) (syscallingThread, bool) {
6815 if pp.status != _Prunning {
6816 return syscallingThread{}, false
6817 }
6818
6819
6820
6821
6822
6823
6824
6825
6826
6827
6828
6829 mp := pp.m.ptr()
6830 if mp == nil {
6831
6832 return syscallingThread{}, false
6833 }
6834 gp := mp.curg
6835 if gp == nil {
6836
6837 return syscallingThread{}, false
6838 }
6839 status := readgstatus(gp) &^ _Gscan
6840
6841
6842
6843
6844 if status != _Gsyscall && status != _Gdeadextra {
6845
6846 return syscallingThread{}, false
6847 }
6848 if !castogscanstatus(gp, status, status|_Gscan) {
6849
6850 return syscallingThread{}, false
6851 }
6852 if gp.m != mp || gp.m.p.ptr() != pp {
6853
6854 casfrom_Gscanstatus(gp, status|_Gscan, status)
6855 return syscallingThread{}, false
6856 }
6857 return syscallingThread{gp, mp, pp, status}, true
6858 }
6859
6860
6861
6862
6863
6864 func (s syscallingThread) gcstopP() {
6865 assertLockHeld(&sched.lock)
6866
6867 s.releaseP(_Pgcstop)
6868 s.pp.gcStopTime = nanotime()
6869 sched.stopwait--
6870 }
6871
6872
6873
6874 func (s syscallingThread) takeP() {
6875 s.releaseP(_Pidle)
6876 }
6877
6878
6879
6880
6881 func (s syscallingThread) releaseP(state uint32) {
6882 if state != _Pidle && state != _Pgcstop {
6883 throw("attempted to release P into a bad state")
6884 }
6885 trace := traceAcquire()
6886 s.pp.m = 0
6887 s.mp.p = 0
6888 atomic.Store(&s.pp.status, state)
6889 if trace.ok() {
6890 trace.ProcSteal(s.pp)
6891 traceRelease(trace)
6892 }
6893 addGSyscallNoP(s.mp)
6894 s.pp.syscalltick++
6895 }
6896
6897
6898 func (s syscallingThread) resume() {
6899 casfrom_Gscanstatus(s.gp, s.status|_Gscan, s.status)
6900 }
6901
6902
6903
6904
6905
6906
6907 func preemptall() bool {
6908 res := false
6909 for _, pp := range allp {
6910 if pp.status != _Prunning {
6911 continue
6912 }
6913 if preemptone(pp) {
6914 res = true
6915 }
6916 }
6917 return res
6918 }
6919
6920
6921
6922
6923
6924
6925
6926
6927
6928
6929
6930 func preemptone(pp *p) bool {
6931 mp := pp.m.ptr()
6932 if mp == nil || mp == getg().m {
6933 return false
6934 }
6935 gp := mp.curg
6936 if gp == nil || gp == mp.g0 {
6937 return false
6938 }
6939 if readgstatus(gp)&^_Gscan == _Gsyscall {
6940
6941 return false
6942 }
6943
6944 gp.preempt = true
6945
6946
6947
6948
6949
6950 gp.stackguard0 = stackPreempt
6951
6952
6953 if preemptMSupported && debug.asyncpreemptoff == 0 {
6954 pp.preempt = true
6955
6956
6957 if castogscanstatus(gp, _Grunning, _Gscanrunning) {
6958 if gp.m == mp {
6959 preemptM(gp)
6960 } else {
6961 casfrom_Gscanstatus(gp, _Gscanrunning, _Grunning)
6962 }
6963 }
6964 }
6965
6966 return true
6967 }
6968
6969 var starttime int64
6970
6971 func schedtrace(detailed bool) {
6972 now := nanotime()
6973 if starttime == 0 {
6974 starttime = now
6975 }
6976
6977 lock(&sched.lock)
6978 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)
6979 if detailed {
6980 print(" gcwaiting=", sched.gcwaiting.Load(), " nmidlelocked=", sched.nmidlelocked, " stopwait=", sched.stopwait, " sysmonwait=", sched.sysmonwait.Load(), "\n")
6981 }
6982
6983
6984
6985 for i, pp := range allp {
6986 h := atomic.Load(&pp.runqhead)
6987 t := atomic.Load(&pp.runqtail)
6988 if detailed {
6989 print(" P", i, ": status=", pp.status, " schedtick=", pp.schedtick, " syscalltick=", pp.syscalltick, " m=")
6990 mp := pp.m.ptr()
6991 if mp != nil {
6992 print(mp.id)
6993 } else {
6994 print("nil")
6995 }
6996 print(" runqsize=", t-h, " gfreecnt=", pp.gFree.size, " timerslen=", len(pp.timers.heap), "\n")
6997 } else {
6998
6999
7000 print(" ")
7001 if i == 0 {
7002 print("[ ")
7003 }
7004 print(t - h)
7005 if i == len(allp)-1 {
7006 print(" ]")
7007 }
7008 }
7009 }
7010
7011 if !detailed {
7012
7013 print(" schedticks=[ ")
7014 for _, pp := range allp {
7015 print(pp.schedtick)
7016 print(" ")
7017 }
7018 print("]\n")
7019 }
7020
7021 if !detailed {
7022 unlock(&sched.lock)
7023 return
7024 }
7025
7026 for mp := allm; mp != nil; mp = mp.alllink {
7027 pp := mp.p.ptr()
7028 print(" M", mp.id, ": p=")
7029 if pp != nil {
7030 print(pp.id)
7031 } else {
7032 print("nil")
7033 }
7034 print(" curg=")
7035 if mp.curg != nil {
7036 print(mp.curg.goid)
7037 } else {
7038 print("nil")
7039 }
7040 print(" mallocing=", mp.mallocing, " throwing=", mp.throwing, " preemptoff=", mp.preemptoff, " locks=", mp.locks, " dying=", mp.dying, " spinning=", mp.spinning, " blocked=", mp.blocked, " lockedg=")
7041 if lockedg := mp.lockedg.ptr(); lockedg != nil {
7042 print(lockedg.goid)
7043 } else {
7044 print("nil")
7045 }
7046 print("\n")
7047 }
7048
7049 forEachG(func(gp *g) {
7050 print(" G", gp.goid, ": status=", readgstatus(gp), "(", gp.waitreason.String(), ") m=")
7051 if gp.m != nil {
7052 print(gp.m.id)
7053 } else {
7054 print("nil")
7055 }
7056 print(" lockedm=")
7057 if lockedm := gp.lockedm.ptr(); lockedm != nil {
7058 print(lockedm.id)
7059 } else {
7060 print("nil")
7061 }
7062 print("\n")
7063 })
7064 unlock(&sched.lock)
7065 }
7066
7067 type updateMaxProcsGState struct {
7068 lock mutex
7069 g *g
7070 idle atomic.Bool
7071
7072
7073 procs int32
7074 }
7075
7076 var (
7077
7078
7079 updatemaxprocs = &godebugInc{name: "updatemaxprocs"}
7080
7081
7082
7083 updateMaxProcsG updateMaxProcsGState
7084
7085
7086
7087
7088
7089
7090
7091
7092
7093
7094
7095
7096
7097
7098
7099
7100
7101
7102
7103
7104
7105
7106
7107
7108
7109
7110
7111
7112
7113
7114
7115
7116
7117
7118
7119
7120
7121
7122
7123
7124
7125
7126
7127
7128
7129
7130
7131
7132 computeMaxProcsLock mutex
7133 )
7134
7135
7136
7137
7138 func defaultGOMAXPROCSUpdateEnable() {
7139 if debug.updatemaxprocs == 0 {
7140
7141
7142
7143
7144
7145
7146
7147
7148
7149
7150
7151 updatemaxprocs.IncNonDefault()
7152 return
7153 }
7154
7155 go updateMaxProcsGoroutine()
7156 }
7157
7158 func updateMaxProcsGoroutine() {
7159 updateMaxProcsG.g = getg()
7160 lockInit(&updateMaxProcsG.lock, lockRankUpdateMaxProcsG)
7161 for {
7162 lock(&updateMaxProcsG.lock)
7163 if updateMaxProcsG.idle.Load() {
7164 throw("updateMaxProcsGoroutine: phase error")
7165 }
7166 updateMaxProcsG.idle.Store(true)
7167 goparkunlock(&updateMaxProcsG.lock, waitReasonUpdateGOMAXPROCSIdle, traceBlockSystemGoroutine, 1)
7168
7169
7170 stw := stopTheWorldGC(stwGOMAXPROCS)
7171
7172
7173 lock(&sched.lock)
7174 custom := sched.customGOMAXPROCS
7175 unlock(&sched.lock)
7176 if custom {
7177 startTheWorldGC(stw)
7178 return
7179 }
7180
7181
7182
7183
7184
7185 newprocs = updateMaxProcsG.procs
7186 lock(&sched.lock)
7187 sched.customGOMAXPROCS = false
7188 unlock(&sched.lock)
7189
7190 startTheWorldGC(stw)
7191 }
7192 }
7193
7194 func sysmonUpdateGOMAXPROCS() {
7195
7196 lock(&computeMaxProcsLock)
7197
7198
7199 lock(&sched.lock)
7200 custom := sched.customGOMAXPROCS
7201 curr := gomaxprocs
7202 unlock(&sched.lock)
7203 if custom {
7204 unlock(&computeMaxProcsLock)
7205 return
7206 }
7207
7208
7209 procs := defaultGOMAXPROCS(0)
7210 unlock(&computeMaxProcsLock)
7211 if procs == curr {
7212
7213 return
7214 }
7215
7216
7217
7218
7219 if updateMaxProcsG.idle.Load() {
7220 lock(&updateMaxProcsG.lock)
7221 updateMaxProcsG.procs = procs
7222 updateMaxProcsG.idle.Store(false)
7223 var list gList
7224 list.push(updateMaxProcsG.g)
7225 injectglist(&list)
7226 unlock(&updateMaxProcsG.lock)
7227 }
7228 }
7229
7230
7231
7232
7233
7234
7235 func schedEnableUser(enable bool) {
7236 lock(&sched.lock)
7237 if sched.disable.user == !enable {
7238 unlock(&sched.lock)
7239 return
7240 }
7241 sched.disable.user = !enable
7242 if enable {
7243 n := sched.disable.runnable.size
7244 globrunqputbatch(&sched.disable.runnable)
7245 unlock(&sched.lock)
7246 for ; n != 0 && sched.npidle.Load() != 0; n-- {
7247 startm(nil, false, false)
7248 }
7249 } else {
7250 unlock(&sched.lock)
7251 }
7252 }
7253
7254
7255
7256
7257
7258 func schedEnabled(gp *g) bool {
7259 assertLockHeld(&sched.lock)
7260
7261 if sched.disable.user {
7262 return isSystemGoroutine(gp, true)
7263 }
7264 return true
7265 }
7266
7267
7268
7269
7270
7271
7272 func mput(mp *m) {
7273 assertLockHeld(&sched.lock)
7274
7275 sched.midle.push(unsafe.Pointer(mp))
7276 sched.nmidle++
7277 checkdead()
7278 }
7279
7280
7281
7282
7283
7284
7285 func mget() *m {
7286 assertLockHeld(&sched.lock)
7287
7288 mp := (*m)(sched.midle.pop())
7289 if mp != nil {
7290 sched.nmidle--
7291 }
7292 return mp
7293 }
7294
7295
7296
7297
7298
7299
7300
7301
7302 func mgetSpecific(mp *m) *m {
7303 assertLockHeld(&sched.lock)
7304
7305 if mp.idleNode.prev == 0 && mp.idleNode.next == 0 {
7306
7307 return nil
7308 }
7309
7310 sched.midle.remove(unsafe.Pointer(mp))
7311 sched.nmidle--
7312
7313 return mp
7314 }
7315
7316
7317
7318
7319
7320
7321 func globrunqput(gp *g) {
7322 assertLockHeld(&sched.lock)
7323
7324 sched.runq.pushBack(gp)
7325 }
7326
7327
7328
7329
7330
7331
7332 func globrunqputhead(gp *g) {
7333 assertLockHeld(&sched.lock)
7334
7335 sched.runq.push(gp)
7336 }
7337
7338
7339
7340
7341
7342
7343
7344 func globrunqputbatch(batch *gQueue) {
7345 assertLockHeld(&sched.lock)
7346
7347 sched.runq.pushBackAll(*batch)
7348 *batch = gQueue{}
7349 }
7350
7351
7352
7353 func globrunqget() *g {
7354 assertLockHeld(&sched.lock)
7355
7356 if sched.runq.size == 0 {
7357 return nil
7358 }
7359
7360 return sched.runq.pop()
7361 }
7362
7363
7364
7365 func globrunqgetbatch(n int32) (gp *g, q gQueue) {
7366 assertLockHeld(&sched.lock)
7367
7368 if sched.runq.size == 0 {
7369 return
7370 }
7371
7372 n = min(n, sched.runq.size, sched.runq.size/gomaxprocs+1)
7373
7374 gp = sched.runq.pop()
7375 n--
7376
7377 for ; n > 0; n-- {
7378 gp1 := sched.runq.pop()
7379 q.pushBack(gp1)
7380 }
7381 return
7382 }
7383
7384
7385 type pMask []uint32
7386
7387
7388 func (p pMask) read(id uint32) bool {
7389 word := id / 32
7390 mask := uint32(1) << (id % 32)
7391 return (atomic.Load(&p[word]) & mask) != 0
7392 }
7393
7394
7395 func (p pMask) set(id int32) {
7396 word := id / 32
7397 mask := uint32(1) << (id % 32)
7398 atomic.Or(&p[word], mask)
7399 }
7400
7401
7402 func (p pMask) clear(id int32) {
7403 word := id / 32
7404 mask := uint32(1) << (id % 32)
7405 atomic.And(&p[word], ^mask)
7406 }
7407
7408
7409 func (p pMask) any() bool {
7410 for i := range p {
7411 if atomic.Load(&p[i]) != 0 {
7412 return true
7413 }
7414 }
7415 return false
7416 }
7417
7418
7419
7420
7421
7422 func (p pMask) resize(nprocs int32) pMask {
7423 maskWords := (nprocs + 31) / 32
7424
7425 if maskWords <= int32(cap(p)) {
7426 return p[:maskWords]
7427 }
7428 newMask := make([]uint32, maskWords)
7429
7430 copy(newMask, p)
7431 return newMask
7432 }
7433
7434
7435
7436
7437
7438
7439
7440
7441
7442
7443
7444
7445 func pidleput(pp *p, now int64) int64 {
7446 assertLockHeld(&sched.lock)
7447
7448 if !runqempty(pp) {
7449 throw("pidleput: P has non-empty run queue")
7450 }
7451 if now == 0 {
7452 now = nanotime()
7453 }
7454 if pp.timers.len.Load() == 0 {
7455 timerpMask.clear(pp.id)
7456 }
7457 idlepMask.set(pp.id)
7458 pp.link = sched.pidle
7459 sched.pidle.set(pp)
7460 sched.npidle.Add(1)
7461 if !pp.limiterEvent.start(limiterEventIdle, now) {
7462 throw("must be able to track idle limiter event")
7463 }
7464 return now
7465 }
7466
7467
7468
7469
7470
7471
7472
7473
7474 func pidleget(now int64) (*p, int64) {
7475 assertLockHeld(&sched.lock)
7476
7477 pp := sched.pidle.ptr()
7478 if pp != nil {
7479
7480 if now == 0 {
7481 now = nanotime()
7482 }
7483 timerpMask.set(pp.id)
7484 idlepMask.clear(pp.id)
7485 sched.pidle = pp.link
7486 sched.npidle.Add(-1)
7487 pp.limiterEvent.stop(limiterEventIdle, now)
7488 }
7489 return pp, now
7490 }
7491
7492
7493
7494
7495
7496
7497
7498
7499
7500
7501
7502 func pidlegetSpinning(now int64) (*p, int64) {
7503 assertLockHeld(&sched.lock)
7504
7505 pp, now := pidleget(now)
7506 if pp == nil {
7507
7508
7509
7510 sched.needspinning.Store(1)
7511 return nil, now
7512 }
7513
7514 return pp, now
7515 }
7516
7517
7518
7519 func runqempty(pp *p) bool {
7520
7521
7522
7523
7524 for {
7525 head := atomic.Load(&pp.runqhead)
7526 tail := atomic.Load(&pp.runqtail)
7527 runnext := atomic.Loaduintptr((*uintptr)(unsafe.Pointer(&pp.runnext)))
7528 if tail == atomic.Load(&pp.runqtail) {
7529 return head == tail && runnext == 0
7530 }
7531 }
7532 }
7533
7534
7535
7536
7537
7538
7539
7540
7541
7542
7543 const randomizeScheduler = raceenabled
7544
7545
7546
7547
7548
7549
7550 func runqput(pp *p, gp *g, next bool) {
7551 if !haveSysmon && next {
7552
7553
7554
7555
7556
7557
7558
7559
7560 next = false
7561 }
7562 if randomizeScheduler && next && randn(2) == 0 {
7563 next = false
7564 }
7565
7566 if next {
7567 retryNext:
7568 oldnext := pp.runnext
7569 if !pp.runnext.cas(oldnext, guintptr(unsafe.Pointer(gp))) {
7570 goto retryNext
7571 }
7572 if oldnext == 0 {
7573 return
7574 }
7575
7576 gp = oldnext.ptr()
7577 }
7578
7579 retry:
7580 h := atomic.LoadAcq(&pp.runqhead)
7581 t := pp.runqtail
7582 if t-h < uint32(len(pp.runq)) {
7583 pp.runq[t%uint32(len(pp.runq))].set(gp)
7584 atomic.StoreRel(&pp.runqtail, t+1)
7585 return
7586 }
7587 if runqputslow(pp, gp, h, t) {
7588 return
7589 }
7590
7591 goto retry
7592 }
7593
7594
7595
7596 func runqputslow(pp *p, gp *g, h, t uint32) bool {
7597 var batch [len(pp.runq)/2 + 1]*g
7598
7599
7600 n := t - h
7601 n = n / 2
7602 if n != uint32(len(pp.runq)/2) {
7603 throw("runqputslow: queue is not full")
7604 }
7605 for i := uint32(0); i < n; i++ {
7606 batch[i] = pp.runq[(h+i)%uint32(len(pp.runq))].ptr()
7607 }
7608 if !atomic.CasRel(&pp.runqhead, h, h+n) {
7609 return false
7610 }
7611 batch[n] = gp
7612
7613 if randomizeScheduler {
7614 for i := uint32(1); i <= n; i++ {
7615 j := cheaprandn(i + 1)
7616 batch[i], batch[j] = batch[j], batch[i]
7617 }
7618 }
7619
7620
7621 for i := uint32(0); i < n; i++ {
7622 batch[i].schedlink.set(batch[i+1])
7623 }
7624
7625 q := gQueue{batch[0].guintptr(), batch[n].guintptr(), int32(n + 1)}
7626
7627
7628 lock(&sched.lock)
7629 globrunqputbatch(&q)
7630 unlock(&sched.lock)
7631 return true
7632 }
7633
7634
7635
7636
7637 func runqputbatch(pp *p, q *gQueue) {
7638 if q.empty() {
7639 return
7640 }
7641 h := atomic.LoadAcq(&pp.runqhead)
7642 t := pp.runqtail
7643 n := uint32(0)
7644 for !q.empty() && t-h < uint32(len(pp.runq)) {
7645 gp := q.pop()
7646 pp.runq[t%uint32(len(pp.runq))].set(gp)
7647 t++
7648 n++
7649 }
7650
7651 if randomizeScheduler {
7652 off := func(o uint32) uint32 {
7653 return (pp.runqtail + o) % uint32(len(pp.runq))
7654 }
7655 for i := uint32(1); i < n; i++ {
7656 j := cheaprandn(i + 1)
7657 pp.runq[off(i)], pp.runq[off(j)] = pp.runq[off(j)], pp.runq[off(i)]
7658 }
7659 }
7660
7661 atomic.StoreRel(&pp.runqtail, t)
7662
7663 return
7664 }
7665
7666
7667
7668
7669
7670 func runqget(pp *p) (gp *g, inheritTime bool) {
7671
7672 next := pp.runnext
7673
7674
7675
7676 if next != 0 && pp.runnext.cas(next, 0) {
7677 return next.ptr(), true
7678 }
7679
7680 for {
7681 h := atomic.LoadAcq(&pp.runqhead)
7682 t := pp.runqtail
7683 if t == h {
7684 return nil, false
7685 }
7686 gp := pp.runq[h%uint32(len(pp.runq))].ptr()
7687 if atomic.CasRel(&pp.runqhead, h, h+1) {
7688 return gp, false
7689 }
7690 }
7691 }
7692
7693
7694
7695 func runqdrain(pp *p) (drainQ gQueue) {
7696 oldNext := pp.runnext
7697 if oldNext != 0 && pp.runnext.cas(oldNext, 0) {
7698 drainQ.pushBack(oldNext.ptr())
7699 }
7700
7701 retry:
7702 h := atomic.LoadAcq(&pp.runqhead)
7703 t := pp.runqtail
7704 qn := t - h
7705 if qn == 0 {
7706 return
7707 }
7708 if qn > uint32(len(pp.runq)) {
7709 goto retry
7710 }
7711
7712 if !atomic.CasRel(&pp.runqhead, h, h+qn) {
7713 goto retry
7714 }
7715
7716
7717
7718
7719
7720
7721
7722
7723 for i := uint32(0); i < qn; i++ {
7724 gp := pp.runq[(h+i)%uint32(len(pp.runq))].ptr()
7725 drainQ.pushBack(gp)
7726 }
7727 return
7728 }
7729
7730
7731
7732
7733
7734 func runqgrab(pp *p, batch *[256]guintptr, batchHead uint32, stealRunNextG bool) uint32 {
7735 for {
7736 h := atomic.LoadAcq(&pp.runqhead)
7737 t := atomic.LoadAcq(&pp.runqtail)
7738 n := t - h
7739 n = n - n/2
7740 if n == 0 {
7741 if stealRunNextG {
7742
7743 if next := pp.runnext; next != 0 {
7744 if pp.status == _Prunning {
7745 if mp := pp.m.ptr(); mp != nil {
7746 if gp := mp.curg; gp == nil || readgstatus(gp)&^_Gscan != _Gsyscall {
7747
7748
7749
7750
7751
7752
7753
7754
7755
7756
7757
7758
7759
7760
7761
7762
7763
7764
7765
7766 if !osHasLowResTimer {
7767 usleep(3)
7768 } else {
7769
7770
7771
7772 osyield()
7773 }
7774 if sched.gcwaiting.Load() {
7775
7776
7777 return 0
7778 }
7779 }
7780 }
7781 }
7782 if !pp.runnext.cas(next, 0) {
7783 continue
7784 }
7785 batch[batchHead%uint32(len(batch))] = next
7786 return 1
7787 }
7788 }
7789 return 0
7790 }
7791 if n > uint32(len(pp.runq)/2) {
7792 continue
7793 }
7794 for i := uint32(0); i < n; i++ {
7795 g := pp.runq[(h+i)%uint32(len(pp.runq))]
7796 batch[(batchHead+i)%uint32(len(batch))] = g
7797 }
7798 if atomic.CasRel(&pp.runqhead, h, h+n) {
7799 return n
7800 }
7801 }
7802 }
7803
7804
7805
7806
7807 func runqsteal(pp, p2 *p, stealRunNextG bool) *g {
7808 t := pp.runqtail
7809 n := runqgrab(p2, &pp.runq, t, stealRunNextG)
7810 if n == 0 {
7811 return nil
7812 }
7813 n--
7814 gp := pp.runq[(t+n)%uint32(len(pp.runq))].ptr()
7815 if n == 0 {
7816 return gp
7817 }
7818 h := atomic.LoadAcq(&pp.runqhead)
7819 if t-h+n >= uint32(len(pp.runq)) {
7820 throw("runqsteal: runq overflow")
7821 }
7822 atomic.StoreRel(&pp.runqtail, t+n)
7823 return gp
7824 }
7825
7826
7827
7828 type gQueue struct {
7829 head guintptr
7830 tail guintptr
7831 size int32
7832 }
7833
7834
7835 func (q *gQueue) empty() bool {
7836 return q.head == 0
7837 }
7838
7839
7840 func (q *gQueue) push(gp *g) {
7841 gp.schedlink = q.head
7842 q.head.set(gp)
7843 if q.tail == 0 {
7844 q.tail.set(gp)
7845 }
7846 q.size++
7847 }
7848
7849
7850 func (q *gQueue) pushBack(gp *g) {
7851 gp.schedlink = 0
7852 if q.tail != 0 {
7853 q.tail.ptr().schedlink.set(gp)
7854 } else {
7855 q.head.set(gp)
7856 }
7857 q.tail.set(gp)
7858 q.size++
7859 }
7860
7861
7862
7863 func (q *gQueue) pushBackAll(q2 gQueue) {
7864 if q2.tail == 0 {
7865 return
7866 }
7867 q2.tail.ptr().schedlink = 0
7868 if q.tail != 0 {
7869 q.tail.ptr().schedlink = q2.head
7870 } else {
7871 q.head = q2.head
7872 }
7873 q.tail = q2.tail
7874 q.size += q2.size
7875 }
7876
7877
7878
7879 func (q *gQueue) pop() *g {
7880 gp := q.head.ptr()
7881 if gp != nil {
7882 q.head = gp.schedlink
7883 if q.head == 0 {
7884 q.tail = 0
7885 }
7886 q.size--
7887 }
7888 return gp
7889 }
7890
7891
7892 func (q *gQueue) popList() gList {
7893 stack := gList{q.head, q.size}
7894 *q = gQueue{}
7895 return stack
7896 }
7897
7898
7899
7900 type gList struct {
7901 head guintptr
7902 size int32
7903 }
7904
7905
7906 func (l *gList) empty() bool {
7907 return l.head == 0
7908 }
7909
7910
7911 func (l *gList) push(gp *g) {
7912 gp.schedlink = l.head
7913 l.head.set(gp)
7914 l.size++
7915 }
7916
7917
7918 func (l *gList) pushAll(q gQueue) {
7919 if !q.empty() {
7920 q.tail.ptr().schedlink = l.head
7921 l.head = q.head
7922 l.size += q.size
7923 }
7924 }
7925
7926
7927 func (l *gList) pop() *g {
7928 gp := l.head.ptr()
7929 if gp != nil {
7930 l.head = gp.schedlink
7931 l.size--
7932 }
7933 return gp
7934 }
7935
7936
7937 func setMaxThreads(in int) (out int) {
7938 lock(&sched.lock)
7939 out = int(sched.maxmcount)
7940 if in > 0x7fffffff {
7941 sched.maxmcount = 0x7fffffff
7942 } else {
7943 sched.maxmcount = int32(in)
7944 }
7945 checkmcount()
7946 unlock(&sched.lock)
7947 return
7948 }
7949
7950
7951
7952
7953
7954
7955
7956
7957
7958
7959
7960
7961
7962 func procPin() int {
7963 gp := getg()
7964 mp := gp.m
7965
7966 mp.locks++
7967 return int(mp.p.ptr().id)
7968 }
7969
7970
7971
7972
7973
7974
7975
7976
7977
7978
7979
7980
7981
7982 func procUnpin() {
7983 gp := getg()
7984 gp.m.locks--
7985 }
7986
7987
7988
7989 func sync_runtime_procPin() int {
7990 return procPin()
7991 }
7992
7993
7994
7995 func sync_runtime_procUnpin() {
7996 procUnpin()
7997 }
7998
7999
8000
8001 func sync_atomic_runtime_procPin() int {
8002 return procPin()
8003 }
8004
8005
8006
8007 func sync_atomic_runtime_procUnpin() {
8008 procUnpin()
8009 }
8010
8011
8012
8013
8014
8015 func internal_sync_runtime_canSpin(i int) bool {
8016
8017
8018
8019
8020
8021 if i >= active_spin || numCPUStartup <= 1 || gomaxprocs <= sched.npidle.Load()+sched.nmspinning.Load()+1 {
8022 return false
8023 }
8024 if p := getg().m.p.ptr(); !runqempty(p) {
8025 return false
8026 }
8027 return true
8028 }
8029
8030
8031
8032 func internal_sync_runtime_doSpin() {
8033 procyield(active_spin_cnt)
8034 }
8035
8036
8037
8038
8039
8040
8041
8042
8043
8044
8045
8046
8047
8048
8049
8050 func sync_runtime_canSpin(i int) bool {
8051 return internal_sync_runtime_canSpin(i)
8052 }
8053
8054
8055
8056
8057
8058
8059
8060
8061
8062
8063
8064
8065
8066 func sync_runtime_doSpin() {
8067 internal_sync_runtime_doSpin()
8068 }
8069
8070 var stealOrder randomOrder
8071
8072
8073
8074
8075
8076 type randomOrder struct {
8077 count uint32
8078 coprimes []uint32
8079 }
8080
8081 type randomEnum struct {
8082 i uint32
8083 count uint32
8084 pos uint32
8085 inc uint32
8086 }
8087
8088 func (ord *randomOrder) reset(count uint32) {
8089 ord.count = count
8090 ord.coprimes = ord.coprimes[:0]
8091 for i := uint32(1); i <= count; i++ {
8092 if gcd(i, count) == 1 {
8093 ord.coprimes = append(ord.coprimes, i)
8094 }
8095 }
8096 }
8097
8098 func (ord *randomOrder) start(i uint32) randomEnum {
8099 return randomEnum{
8100 count: ord.count,
8101 pos: i % ord.count,
8102 inc: ord.coprimes[i/ord.count%uint32(len(ord.coprimes))],
8103 }
8104 }
8105
8106 func (enum *randomEnum) done() bool {
8107 return enum.i == enum.count
8108 }
8109
8110 func (enum *randomEnum) next() {
8111 enum.i++
8112 enum.pos = (enum.pos + enum.inc) % enum.count
8113 }
8114
8115 func (enum *randomEnum) position() uint32 {
8116 return enum.pos
8117 }
8118
8119 func gcd(a, b uint32) uint32 {
8120 for b != 0 {
8121 a, b = b, a%b
8122 }
8123 return a
8124 }
8125
8126
8127
8128 type initTask struct {
8129 state uint32
8130 nfns uint32
8131
8132 }
8133
8134
8135
8136 var inittrace tracestat
8137
8138 type tracestat struct {
8139 active bool
8140 id uint64
8141 allocs uint64
8142 bytes uint64
8143 }
8144
8145 func doInit(ts []*initTask) {
8146 for _, t := range ts {
8147 doInit1(t)
8148 }
8149 }
8150
8151 func doInit1(t *initTask) {
8152 switch t.state {
8153 case 2:
8154 return
8155 case 1:
8156 throw("recursive call during initialization - linker skew")
8157 default:
8158 t.state = 1
8159
8160 var (
8161 start int64
8162 before tracestat
8163 )
8164
8165 if inittrace.active {
8166 start = nanotime()
8167
8168 before = inittrace
8169 }
8170
8171 if t.nfns == 0 {
8172
8173 throw("inittask with no functions")
8174 }
8175
8176 firstFunc := add(unsafe.Pointer(t), 8)
8177 for i := uint32(0); i < t.nfns; i++ {
8178 p := add(firstFunc, uintptr(i)*goarch.PtrSize)
8179 f := *(*func())(unsafe.Pointer(&p))
8180 f()
8181 }
8182
8183 if inittrace.active {
8184 end := nanotime()
8185
8186 after := inittrace
8187
8188 f := *(*func())(unsafe.Pointer(&firstFunc))
8189 pkg := funcpkgpath(findfunc(abi.FuncPCABIInternal(f)))
8190
8191 var sbuf [24]byte
8192 print("init ", pkg, " @")
8193 print(string(fmtNSAsMS(sbuf[:], uint64(start-runtimeInitTime))), " ms, ")
8194 print(string(fmtNSAsMS(sbuf[:], uint64(end-start))), " ms clock, ")
8195 print(string(itoa(sbuf[:], after.bytes-before.bytes)), " bytes, ")
8196 print(string(itoa(sbuf[:], after.allocs-before.allocs)), " allocs")
8197 print("\n")
8198 }
8199
8200 t.state = 2
8201 }
8202 }
8203
View as plain text